passing authentication token from 1 HTTP triggered function to another
Hi
I am using durable functions monitor in injected mode and not using the inbuilt authentication provided in function app. Rather I am generating auth code and auth token using Microsoft identity platform auth code flow.
I have below function that when accessed presents the sign in screen
[Function("Function1")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
string tenant = "tenantId"; // or use your tenant ID
string clientId = "clientId";
// Ensure this redirect URI matches what is in your app registration
string redirectUri = "http://localhost:7267/api/Function2";
// Define the scopes you need (openid, profile, offline_access, etc.)
string scope = "openid profile email";
string authUrl = $"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize" +
$"?client_id={clientId}" +
$"&response_type=code" +
$"&redirect_uri={WebUtility.UrlEncode(redirectUri)}" +
$"&response_mode=query" +
$"&scope={WebUtility.UrlEncode(scope)}" +
$"&state=12345&prompt=login"; // ideally, generate a dynamic state value
var response = req.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Add("Location", authUrl);
return response;
}
This redirects me to Function2 where I get the auth token as below
[Function("Function2")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
string code = req.Query["code"]!;
string tenant = "tenantId"; // or your tenant-specific ID
string clientId = "clientId";
string clientSecret = "secret";
string redirectUri = "http://localhost:7267/api/Function2";
// Build the MSAL confidential client application
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithRedirectUri(redirectUri)
.WithAuthority($"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token")
.Build();
AuthenticationResult result = app.AcquireTokenByAuthorizationCode(
new string[] { "openid", "profile", "email" }, code)
.ExecuteAsync().Result;
if (result.AccessToken != null)
{
var response = req.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Add("Location", "http://localhost:7267/api/DFM");
response.Headers.Add("Authorization", result.AccessToken);
return response;
}
else
{
return req.CreateResponse(HttpStatusCode.BadRequest);
}
}
The endpoint http://localhost:7267/api/DFM is my custom endpoint for the durable function monitor in injected mode
[Function(nameof(MyCustomDfMonEndpoint))]
public Task<HttpResponseData> ServeDfMonStatics(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Globals.DfMonRoutePrefix + "/{p1?}/{p2?}/{p3?}")] HttpRequestData req,
string p1,
string p2,
string p3
)
{
if (!req.Headers.TryGetValues("Authorization", out var authHeaders))
{
var unauthorizedResponse = req.CreateResponse(HttpStatusCode.Unauthorized);
unauthorizedResponse.WriteStringAsync("Missing Authorization header.");
return Task.FromResult(unauthorizedResponse);
}
return this.DfmServeStaticsFunction(req, p1, p2, p3);
}
Currently what I am seeing is the endpoint for DFM doesn't get the token in headers passed from Function2 using response.Headers.Add("Authorization", result.AccessToken);
What I am looking for is getting the token in the headers when it is redirected from Function2 and maintaining that token when the links on the durable function monitor are hit. so that the below check always prevents unauthorized access
if (!req.Headers.TryGetValues("Authorization", out var authHeaders))
{
var unauthorizedResponse = req.CreateResponse(HttpStatusCode.Unauthorized);
unauthorizedResponse.WriteStringAsync("Missing Authorization header.");
return Task.FromResult(unauthorizedResponse);
}