mrkeyoor.com_
Thu 06 Aug 10:59 UTC
npmSecurityupdated 06 Aug 2026

@azure/identity

Every Azure SDK client for JavaScript takes a TokenCredential in its constructor and calls getToken on it when it needs a Microsoft Entra ID access token. @azure/identity is the package that supplies those credential objects. Each class knows one way to obtain a token: from environment variables, from the managed identity attached to an Azure host, from a Kubernetes federated token file, from a service principal secret, certificate, or signed assertion, or from whoever is signed in to the Azure CLI, the Azure Developer CLI, Azure PowerShell, or VS Code. The headline class, DefaultAzureCredential, chains eight of them in a fixed order so the same file can run on a laptop and in production without a branch. Most of the actual protocol work happens in MSAL, which this package wraps.

Verdict

The correct and effectively required way to authenticate Azure SDK clients from Node, and managed identity support here is the reason production code can hold zero secrets. Use DefaultAzureCredential while you develop, then pin the deployed build to one credential with AZURE_TOKEN_CREDENTIALS or an explicit chain.

API stability4/5The TokenCredential shape and the credential class names have held since 1.0, and newer pieces such as WorkloadIdentityCredential, AzurePipelinesCredential, and the AZURE_TOKEN_CREDENTIALS switch arrived as additions. Behaviour inside DefaultAzureCredential does move between minors, and the 4.13.1 upgrade to MSAL v5 changed enough internally that the release notes read like a migration rather than a patch.
Docs5/5The README tables every credential class with when to use it, lists the environment variables per authentication type, and states plainly which scenarios are unsupported. Microsoft Learn adds a troubleshooting guide keyed to the actual error strings, and a separate examples page covers custom credentials and using MSAL directly when this package is the wrong layer.
Maintenance4/5Microsoft develops it inside the azure-sdk-for-js monorepo, which had commits on the day of this review. Stable releases lag the activity: 4.13.1 shipped in March 2026 and the 4.14 line has been in beta since November 2025. The 530 open issues on that tracker cover every package in the monorepo, not this one, so filing here means joining a large shared queue.
Ecosystem5/5About 14.5M downloads a week and a dependency of essentially every Azure SDK client for JavaScript, which makes credentials interchangeable across them. Three first-party plugin packages cover the broker, VS Code, and persistent caching.

Use it if

  • You call any Azure SDK client from Node or TypeScript, since Key Vault, Blob Storage, Service Bus, Cosmos, and the management libraries all expect a TokenCredential and this is what produces one
  • You deploy to App Service, Functions, Container Apps, AKS, Arc, Service Fabric, or a VM and want managed identity so no secret exists in your configuration at all
  • You want local development to authenticate as the signed-in developer through az login or the Azure Developer CLI while the deployed build authenticates as its workload identity, from unchanged source
  • You need a token outside the SDK too: getBearerTokenProvider hands the OpenAI client a callback that refreshes itself, and getToken covers direct REST calls
  • You run on Azure Pipelines and want workload identity federation through a service connection, which AzurePipelinesCredential covers without storing a secret in the pipeline
Skip it if

Setup reality

npm install @azure/identity needs Node 20 or newer and brings eleven dependencies, dominated by @azure/msal-node and @azure/msal-browser. Nothing compiles. The work is in the environment and in the pieces sold separately. VS Code sign-in stopped working from the base package: you now install @azure/identity-vscode v2 or later and call useIdentityPlugin before constructing the credential. Persistent token caching needs @azure/identity-cache-persistence and a working OS keychain, and the Windows broker needs @azure/identity-broker; without them tokens live in memory only and interactive sign-in repeats on every process start. A user-assigned managed identity requires you to pass managedIdentityClientId or managedIdentityResourceId, because the default asks for the system-assigned one and a host with several identities hands back a token that produces a 403 from the target service rather than an auth error. Sovereign clouds need authorityHost or AZURE_AUTHORITY_HOST, and credentials backed by a developer tool ignore both and follow whatever that tool is configured for. When a chain fails you get one AggregateAuthenticationError whose message concatenates every link's failure, and the line you need is rarely the first one.

Patterns

Authenticate an SDK clientdefault-credential

import { DefaultAzureCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";

const credential = new DefaultAzureCredential();

const client = new SecretClient(
  "https://my-vault.vault.azure.net",
  credential
);

const secret = await client.getSecret("db-password");

Build the credential once at module scope and share it. It caches tokens in memory, so constructing a new one per request throws that cache away and goes back to Entra ID every time.

Pin production to one credentialnarrow-the-chain

# no code change: set the env var on the deployed app
AZURE_TOKEN_CREDENTIALS=prod                     # env, workload identity, managed identity
AZURE_TOKEN_CREDENTIALS=dev                      # developer tools only
AZURE_TOKEN_CREDENTIALS=managedidentitycredential # exactly one

# anything else throws at construction:
# Invalid value for AZURE_TOKEN_CREDENTIALS = ...

This is the highest-value change to make before deploying, and in JavaScript it is the only built-in way to narrow the chain, since there are no exclude options on DefaultAzureCredentialOptions. Setting it to managedidentitycredential also skips the probe request, which takes a chunk out of cold start.

Define the fallback order yourselfexplicit-chain

import {
  ChainedTokenCredential,
  ManagedIdentityCredential,
  AzureCliCredential,
} from "@azure/identity";

const credential = new ChainedTokenCredential(
  new ManagedIdentityCredential({ clientId: process.env.UAMI_CLIENT_ID }),
  new AzureCliCredential()
);

Two credentials you chose beats the eight-step default chain: the order is explicit, the aggregate error message stays short, and there is no path by which the process authenticates as an identity you did not intend.

Target a specific managed identityuser-assigned-managed-identity

import { ManagedIdentityCredential } from "@azure/identity";

// user-assigned: pass exactly one of clientId, resourceId, objectId
const credential = new ManagedIdentityCredential({
  clientId: "11111111-2222-3333-4444-555555555555",
});

// system-assigned: no options
// const credential = new ManagedIdentityCredential();

On a host with more than one user-assigned identity, omitting the id gets a token for whichever the platform treats as default, and the symptom is a 403 from the service you are calling rather than an authentication failure. Use resourceId when an ARM template created the identity and the client id is not known ahead of time.

Authenticate a pod on AKSworkload-identity

import { WorkloadIdentityCredential } from "@azure/identity";

const credential = new WorkloadIdentityCredential({
  tenantId: process.env.AZURE_TENANT_ID,
  clientId: process.env.AZURE_CLIENT_ID,
  tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE,
});

Those three variables are injected by the AKS workload identity webhook, so DefaultAzureCredential already finds this path. Constructing it directly is worth it when you want a misconfiguration to fail loudly instead of falling through to the next credential in the chain.

Authenticate a service principalservice-principal

import {
  ClientSecretCredential,
  ClientCertificateCredential,
} from "@azure/identity";

const bySecret = new ClientSecretCredential(
  process.env.AZURE_TENANT_ID,
  process.env.AZURE_CLIENT_ID,
  process.env.AZURE_CLIENT_SECRET
);

const byCert = new ClientCertificateCredential(
  process.env.AZURE_TENANT_ID,
  process.env.AZURE_CLIENT_ID,
  { certificatePath: "/secrets/sp.pem" }
);

Setting AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET and using EnvironmentCredential gets the same result with no credential material in the code path. Prefer a certificate over a secret where the platform allows it, and managed identity over both.

Call Azure OpenAI without an API keybearer-token-provider

import { DefaultAzureCredential, getBearerTokenProvider } from "@azure/identity";
import { AzureOpenAI } from "openai";

const getToken = getBearerTokenProvider(
  new DefaultAzureCredential(),
  "https://cognitiveservices.azure.com/.default"
);

const client = new AzureOpenAI({
  endpoint: "https://my-resource.openai.azure.com",
  azureADTokenProvider: getToken,
  apiVersion: "2024-10-21",
});

The provider is a plain async callback returning a token string, so refresh is handled for you and it drops into anything that accepts one. The identity still needs the Cognitive Services OpenAI User role on the resource, which is the step people miss after removing the key.

Get a token for your own HTTP callraw-token

const credential = new DefaultAzureCredential();

const token = await credential.getToken(
  "https://management.azure.com/.default"
);

const res = await fetch(
  "https://management.azure.com/subscriptions?api-version=2022-12-01",
  { headers: { Authorization: `Bearer ${token.token}` } }
);

Scopes end in /.default for application permissions and the resource must match the API being called. token.expiresOnTimestamp is milliseconds since the epoch; the credential caches internally, so calling getToken again is cheap rather than another round trip.

Separate an unavailable credential from a rejected oneerror-handling

import {
  CredentialUnavailableError,
  AuthenticationError,
  AggregateAuthenticationError,
} from "@azure/identity";

try {
  await credential.getToken("https://vault.azure.net/.default");
} catch (err) {
  if (err instanceof AggregateAuthenticationError) {
    for (const inner of err.errors) log.error(inner);
  } else if (err instanceof CredentialUnavailableError) {
    // nothing to try: no env vars, no signed-in CLI, no IMDS
  } else if (err instanceof AuthenticationError) {
    // Entra ID said no: wrong tenant, expired secret, no consent
  }
  throw err;
}

CredentialUnavailableError is what lets a chain move on to the next link, so a chain only surfaces it when every link was unavailable. AggregateAuthenticationError carries an errors array, which is far easier to read than the concatenated message string.

Refuse to start with missing configurationfail-fast-config

const credential = new DefaultAzureCredential({
  requiredEnvVars: ["AZURE_CLIENT_ID", "AZURE_TENANT_ID"],
  processTimeoutInMs: 3000,
});

requiredEnvVars throws in the constructor listing everything missing, which turns a deployment mistake into a startup crash instead of a 403 on the first user request. processTimeoutInMs caps how long the CLI-based credentials may block, which matters when a developer tool hangs waiting for input.

Enable VS Code sign-in during local developmentvscode-plugin

import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
import { vsCodePlugin } from "@azure/identity-vscode";

useIdentityPlugin(vsCodePlugin);

const credential = new DefaultAzureCredential();

VisualStudioCodeCredential does nothing on its own now; it needs @azure/identity-vscode v2 or later registered before the credential is constructed, plus the Azure Resources extension and an active sign-in. Skipping the plugin is why the chain silently falls through to the Azure CLI instead.

Authenticate against a non-public cloudsovereign-cloud

import { AzureAuthorityHosts, ClientSecretCredential } from "@azure/identity";

const credential = new ClientSecretCredential(tenantId, clientId, secret, {
  authorityHost: AzureAuthorityHosts.AzureGovernment,
});

// or once, for every credential:
// AZURE_AUTHORITY_HOST=https://login.partner.microsoftonline.cn

Credentials that shell out to a developer tool, such as AzureCliCredential, ignore this setting and use whatever cloud that tool is logged into, so a half-configured machine can end up talking to two clouds in one process.

Alternatives

PackageRegistryPick it when
@azure/msal-nodenpmYou want direct control of the token flow and its caching, and you are not passing credentials into Azure SDK clients
@azure/msal-browsernpmYou are authenticating users in a single-page app and do not want the Node-oriented credential surface in your bundle
@azure/identity-brokernpmYou ship a Windows desktop app and want brokered sign-in through the Web Account Manager instead of a browser redirect
@azure/identity-cache-persistencenpmYou build a CLI or desktop tool and need the token cache to survive a restart so users do not sign in every time