Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure Function To Azure Function Request using DefaultAzureCredential and HttpClient

I need to call a Http Azure Function from another Azure Function.

At present, I call an Azure Key Vault to get the target Function's Key, and put that in the URL as documented here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=csharp#api-key-authorization

However, I want to start using a Managed Identity and DefaultAzureCredential but I cannot find out how to use DefaultAzureCredential with HttpClient or similar.

How could I use DefaultAzureCredential and HttpClient to call a Function from another Function?

like image 730
EnenDaveyBoy Avatar asked Sep 07 '26 15:09

EnenDaveyBoy


1 Answers

The simplistic way of solving this issue is like this:

var targetFunctionAppAppRegistrationApplicationId = "A Guid that you must get from your target Function's Authentication configuration - 'App (client) ID'";
var url = "https://yourfunctionappname.azurewebsites.net/api/targetfunctionname";
var creds = new DefaultAzureCredential();
var token = await creds.GetTokenAsync(new Azure.Core.TokenRequestContext(new[] { targetFunctionAppAppRegistrationApplicationId }));
using (HttpClient client = new HttpClient())
{
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
  var result = await client.GetAsync(url);
  // Anything else you want to do with the result
}

Credits for the above to https://spblog.net/post/2021/09/28/call-azure-ad-secured-azure-function-from-logic-app-or-another-function-with-managed-identity

However

The code above will soon cause socket exhaustion. The correct way is to use HttpClientFactory, as explained here: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

Since this specific use case is not covered in those docs, below is an example of how it would look like.

First, you need a MessageHandler:

public class AzureDefaultCredentialsAuthorizationMessageHandler : DelegatingHandler
{
  private readonly TokenRequestContext TokenRequestContext;
  private readonly DefaultAzureCredential Credentials;

  public AzureDefaultCredentialsAuthorizationMessageHandler()
  {
    // This parameter is actually a list of scopes.
    // If your target Function has defined scopes then you should use them here.
    // TokenRequestContext also supports many other options you should probably check out.
    TokenRequestContext = new (new[] { "targetFunctionAppAppRegistrationApplicationId" }); 
    Credentials = new DefaultAzureCredential();
  }

  protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var tokenResult = await Credentials.GetTokenAsync(TokenRequestContext, cancellationToken);
    var authorizationHeader = new AuthenticationHeaderValue("Bearer", tokenResult.Token);
    request.Headers.Authorization = authorizationHeader;
    return await base.SendAsync(request, cancellationToken);
  }
}

You then need to register an HttpClient with this message handler in your Dependency Injection container. If you're using the standard IServiceCollection:

services
  .AddScoped<AzureDefaultCredentialsAuthorizationMessageHandler>()
  .AddHttpClient<YourClassUsingTheHttpClient>((serviceProvider, httpClient) => 
  {
    httpClient.BaseAddress = "https://yourfunctionappname.azurewebsites.net/api/targetfunctionname";
  }).AddHttpMessageHandler<AzureDefaultCredentialsAuthorizationMessageHandler>();

Finally, just have a YourClassUsingTheHttpClient class that takes an HttpClient in its constructor:

public class YourClassUsingTheHttpClient
{
  public YourClassUsingTheHttpClient(HttpClient httpClient) { ... }
}

Notes

It should be noted that the code above does not deal with other important concerns like:

  1. Error handling
  2. Token caching
  3. Ability to have different HttpClients and MessageHandlers for different API endpoints.

Error handler should be straightforward to add. The rest go beyond the scope of this question.

like image 159
Rodolfo Grave Avatar answered Sep 10 '26 05:09

Rodolfo Grave



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!