Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft EdgeMore info about Internet Explorer and Microsoft Edge
Table of contentsExit editor mode

Authentication best practices with the Azure Identity library for JavaScript

Feedback

In this article

This article offers guidelines to help you maximize the performance and reliability of your JavaScript and TypeScript apps when authenticating to Azure services. To make the most of the Azure Identity library for JavaScript, 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 JavaScript app hosted on an Azure Virtual Machine (VM) successfully usesDefaultAzureCredential to authenticate via managed identity.
  3. Without telling the support team, a developer installs the Azure CLI on that VM and runs theaz login command to authenticate to Azure.
  4. Due to this new separate configuration change in the Azure environment, authentication via the original managed identity unexpectedly begins to fail silently.
  5. DefaultAzureCredential skips the failedManagedIdentityCredential and searches for the next available credential, which isAzureCliCredential.
  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, replaceDefaultAzureCredential with a specificTokenCredential implementation, such asManagedIdentityCredential. See theAzure Identity client library documentation for available credentials.

For example, consider the followingDefaultAzureCredential configuration in an Express.js project:

import { DefaultAzureCredential } from "@azure/identity";import { SecretClient } from "@azure/keyvault-secrets";import { BlobServiceClient } from "@azure/storage-blob";const credential = new DefaultAzureCredential();const secretClient = new SecretClient("https://keyVaultName.vault.azure.net", credential);const blobServiceClient = new BlobServiceClient(  "https://storageAccountName.blob.core.windows.net",  credential);

Modify the preceding code to select a credential based on the environment in which the app is running:

import { AzureDeveloperCliCredential, ManagedIdentityCredential, ChainedTokenCredential,          AzureCliCredential } from "@azure/identity";import { SecretClient } from "@azure/keyvault-secrets";import { BlobServiceClient } from "@azure/storage-blob";let credential;// In production, use only ManagedIdentityCredentialif (process.env.NODE_ENV === 'production') {  // For user-assigned managed identity, provide the client ID  credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID);}// In development, use a chain of credentials appropriate for local workelse {  credential = new ChainedTokenCredential(    new AzureCliCredential(),    new AzureDeveloperCliCredential()  );}// Initialize Key Vault clientconst secretClient = new SecretClient("https://keyVaultName.vault.azure.net", credential);// Initialize Blob Storage clientconst blobServiceClient = new BlobServiceClient(  "https://storageAccountName.blob.core.windows.net",  credential);

In this example, onlyManagedIdentityCredential is used in production. The local development environment's authentication needs are then serviced by the sequence of credentials defined in theelse clause.

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, seeToken caching in the Azure Identity client library.

Token caching behavior differs between browser and Node.js environments. In Node.js applications, tokens are cached in memory by default, which means the cache is lost when the application restarts. In browser applications, tokens can be persisted in browser storage (localStorage orsessionStorage) depending on the authentication flow and configuration. Understanding these differences is important when implementing credential reuse strategies for different application types.

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 application framework.

To implement credential reuse in JavaScript applications, create a single credential instance and reuse it across all client objects:

import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";import { SecretClient } from "@azure/keyvault-secrets";import { BlobServiceClient } from "@azure/storage-blob";// Create a single credential instanceconst credential = process.env.NODE_ENV === 'production'  ? new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID)  : new DefaultAzureCredential();// Reuse the credential across different client objectsconst secretClient = new SecretClient("https://keyVaultName.vault.azure.net", credential);const blobServiceClient = new BlobServiceClient(  "https://storageAccountName.blob.core.windows.net",  credential);

In Express.js applications, you can store the credential in app settings and access it in your route handlers:

import express from "express";import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";import { SecretClient } from "@azure/keyvault-secrets";import { BlobServiceClient } from "@azure/storage-blob";const app = express();// Create a single credential instance at app startupapp.locals.credential = process.env.NODE_ENV === 'production'  ? new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID)  : new DefaultAzureCredential();// Reuse the credential in route handlersapp.get('/api/secrets/:secretName', async (req, res) => {  const secretClient = new SecretClient(    "https://keyVaultName.vault.azure.net",     req.app.locals.credential  );    try {    const secret = await secretClient.getSecret(req.params.secretName);    res.json({ name: secret.name, value: secret.value });  } catch (error) {    res.status(500).json({ error: error.message });  }});// Add this route to the existing Express appapp.get('/api/blobs/:containerName', async (req, res) => {  const blobServiceClient = new BlobServiceClient(    "https://storageAccountName.blob.core.windows.net",     req.app.locals.credential  );    try {    // Get reference to a container    const containerClient = blobServiceClient.getContainerClient(req.params.containerName);        // List all blobs in the container    const blobs = [];    for await (const blob of containerClient.listBlobsFlat()) {      blobs.push({        name: blob.name,        contentType: blob.properties.contentType,        size: blob.properties.contentLength,        lastModified: blob.properties.lastModified      });    }        res.json({ containerName: req.params.containerName, blobs });  } catch (error) {    res.status(500).json({ error: error.message });  }});app.listen(3000, () => console.log('Server running on port 3000'));

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, it becomes your responsibility to managetoken lifetime and caching behavior in your app.

TherefreshAfterTimestamp property onAccessToken, 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 therefreshAfterTimestamp time occurs. This design allows the client code to callTokenCredential.getToken() each time a token is needed and delegate the refresh to the library.

To only callTokenCredential.getToken() when necessary, observe therefreshAfterTimestamp 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 JavaScript allows you to authenticate via managed identity withManagedIdentityCredential. The way in which you useManagedIdentityCredential impacts the applied retry strategy:

  • When used viaDefaultAzureCredential, 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 asChainedTokenCredential orManagedIdentityCredential 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 theretryOptions property on options parameter. For example, retry a maximum of three times, with a starting interval of 0.5 seconds:
import { ManagedIdentityCredential } from "@azure/identity";const credential = new ManagedIdentityCredential(  process.env.AZURE_CLIENT_ID, // For user-assigned managed identity  {    retryOptions: {      maxRetries: 3,           // Maximum number of retry attempts      retryDelayInMs: 500,     // Initial delay between retries (in milliseconds)      maxRetryDelayInMs: 5000  // Maximum delay between retries (in milliseconds)    }  });

For more information on customizing retry policies for managed identity, see one of the following options that extend fromTokenCredentialOptions:


Feedback

Was this page helpful?

YesNoNo

Need help with this topic?

Want to try using Ask Learn to clarify or guide you through this topic?

Suggest a fix?

  • Last updated on

In this article

Was this page helpful?

YesNo
NoNeed help with this topic?

Want to try using Ask Learn to clarify or guide you through this topic?

Suggest a fix?