Rediger

Del via


Authentication best practices with the Azure Identity library for .NET

This article offers guidelines to help you maximize the performance and reliability of your .NET apps when authenticating to Azure services. To make the most of the Azure Identity library for .NET, it's important to understand potential issues and mitigation techniques.

Use deterministic credentials in production environments

DefaultAzureCredential is the most approachable way to get started with the Azure Identity library, but that convenience also introduces certain tradeoffs. Most notably, the specific credential in the chain that will succeed and be used for request authentication can't be guaranteed ahead of time. In a production environment, this unpredictability can introduce significant and sometimes subtle problems.

For example, consider the following hypothetical sequence of events:

  1. An organization's security team mandates all apps use managed identity to authenticate to Azure resources.
  2. For months, a .NET app hosted on an Azure Virtual Machine (VM) successfully uses DefaultAzureCredential to authenticate via managed identity.
  3. Without telling the support team, a developer installs the Azure CLI on that VM and runs the az login command to authenticate to Azure.
  4. Due to a separate configuration change in the Azure environment, authentication via the original managed identity unexpectedly begins to fail silently.
  5. DefaultAzureCredential skips the failed ManagedIdentityCredential and searches for the next available credential, which is AzureCliCredential.
  6. The application starts utilizing the Azure CLI credentials rather than the managed identity, which may fail or result in unexpected elevation or reduction of privileges.

To prevent these types of subtle issues or silent failures in production apps, strongly consider moving from DefaultAzureCredential to one of the following deterministic solutions:

  • A specific TokenCredential implementation, such as ManagedIdentityCredential. See the Derived list for options.
  • A pared-down ChainedTokenCredential implementation optimized for the Azure environment in which your app runs. ChainedTokenCredential essentially creates a specific allowlist of acceptable credential options, such as ManagedIdentity for production and VisualStudioCredential for development.

For example, consider the following DefaultAzureCredential configuration in an ASP.NET Core project:

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddBlobServiceClient(
        new Uri("https://<account-name>.blob.core.windows.net"));

    DefaultAzureCredential credential = new();
    clientBuilder.UseCredential(credential);
});

Replace the preceding code with a ChainedTokenCredential implementation that specifies only the necessary credentials:

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddBlobServiceClient(
        new Uri("https://<account-name>.blob.core.windows.net"));

    clientBuilder.UseCredential(new ChainedTokenCredential(
        new ManagedIdentityCredential(clientId: userAssignedClientId),
        new VisualStudioCredential()));
});

In this example, ManagedIdentityCredential would be automatically discovered in production, while VisualStudioCredential would work in local development environments.

Reuse credential instances

Reuse credential instances when possible to improve app resilience and reduce the number of access token requests issued to Microsoft Entra ID. When a credential is reused, an attempt is made to fetch a token from the app token cache managed by the underlying MSAL dependency. For more information, see Token caching in the Azure Identity client library.

Important

A high-volume app that doesn't reuse credentials may encounter HTTP 429 throttling responses from Microsoft Entra ID, which can lead to app outages.

The recommended credential reuse strategy differs by .NET application type.

Implement credential reuse through the UseCredential method of Microsoft.Extensions.Azure. For example, imagine an ASP.NET Core app hosted on Azure App Service, with a UserAssignedClientId environment variable set. The .NET configuration provider determines the environment variable exists, and ManagedIdentityCredential will be used to authenticate the Key Vault Secrets and Blob Storage clients. Otherwise, a chained sequence of development-time credentials is used.

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddSecretClient(new Uri("<key-vault-url>"));
    clientBuilder.AddBlobServiceClient(new Uri("<blob-storage-url>"));

    string? clientId = builder.Configuration["UserAssignedClientId"];

    TokenCredential credential = clientId is not null
        ? new ManagedIdentityCredential(
            ManagedIdentityId.FromUserAssignedClientId(clientId))
        : new ChainedTokenCredential(
            new VisualStudioCredential(),
            new AzureCliCredential(),
            new AzurePowerShellCredential());

    clientBuilder.UseCredential(credential);
});

For information on this approach, see Authenticate using Microsoft Entra ID.

Understand when token lifetime and caching logic is needed

If you use an Azure Identity library credential outside the context of an Azure SDK client library that depends on Azure Core, it becomes your responsibility to manage token lifetime and caching behavior in your app.

The RefreshOn property on AccessToken, which provides a hint to consumers as to when token refresh can be attempted, will be automatically used by Azure SDK client libraries that depend on the Azure Core library to refresh the token. For direct usage of Azure Identity library credentials that support token caching, the underlying MSAL cache automatically refreshes proactively when the RefreshOn time occurs. This design allows the client code to call GetToken each time a token is needed and delegate the refresh to the library.

To only call GetToken when necessary, observe the RefreshOn date and proactively attempt to refresh the token after that time. The specific implementation is up to the customer.

Understand the managed identity retry strategy

The Azure Identity library for .NET allows you to authenticate via managed identity with ManagedIdentityCredential. The way in which you use ManagedIdentityCredential impacts the applied retry strategy. When used via:

  • DefaultAzureCredential, no retries are attempted when the initial token acquisition attempt fails or times out after a short duration. This is the least resilient option because it's optimized to "fail fast" for an efficient development inner loop.
  • Any other approach, such as ChainedTokenCredential or ManagedIdentityCredential directly:
    • The time interval between retries starts at 0.8 seconds, and a maximum of five retries are attempted, by default. This option is optimized for resilience but introduces potentially unwanted delays in the development inner loop.

    • To change any of the default retry settings, use the Retry property on ManagedIdentityCredentialOptions. For example, retry a maximum of three times, with a starting interval of 0.5 seconds:

      ManagedIdentityCredentialOptions miCredentialOptions = new(
              ManagedIdentityId.FromUserAssignedClientId(clientId)
          )
          {
              Retry =
              {
                  MaxRetries = 3,
                  Delay = TimeSpan.FromSeconds(0.5),
              }
          };
          ChainedTokenCredential tokenChain = new(
              new ManagedIdentityCredential(miCredentialOptions),
              new VisualStudioCredential()
          );
      

For more information on customizing retry policies, see Setting a custom retry policy.