Skip to content

Commit bd4b22f

Browse files
[Identity] update the DAC chain based on env var AZURE_TOKEN_CREDENTIALS (#34301)
1 parent c662c13 commit bd4b22f

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

sdk/identity/identity/CHANGELOG.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
# Release History
22

3-
## 4.9.2 (Unreleased)
4-
5-
### Features Added
6-
7-
### Breaking Changes
8-
9-
### Bugs Fixed
3+
## 4.9.2 (2025-05-14)
104

115
### Other Changes
126

7+
- Added support for the `AZURE_TOKEN_CREDENTIALS` environment variable to `DefaultAzureCredential`, which allows for choosing between 'deployed service' and 'developer tools' credentials. Valid values are 'dev' for developer tools and 'prod' for deployed service.
138
- Added deprecation warnings for username password usage in `EnvironmentCredential` constructor to warn the users. `UsernamePassword` authentication doesn't support Multi-Factor Authentication (MFA), and MFA will enabled soon on all tenants. For more details, see [Planning for mandatory MFA](https://aka.ms/mfaforazure).
149

1510
## 4.9.1 (2025-04-17)

sdk/identity/identity/src/credentials/defaultAzureCredential.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,47 @@ export class DefaultAzureCredential extends ChainedTokenCredential {
233233
constructor(options?: DefaultAzureCredentialOptions);
234234

235235
constructor(options?: DefaultAzureCredentialOptions) {
236-
const credentialFunctions = [
237-
createEnvironmentCredential,
238-
createDefaultWorkloadIdentityCredential,
239-
createDefaultManagedIdentityCredential,
236+
// If AZURE_TOKEN_CREDENTIALS is not set, use the default credential chain.
237+
const azureTokenCredentials = process.env.AZURE_TOKEN_CREDENTIALS
238+
? process.env.AZURE_TOKEN_CREDENTIALS.trim().toLowerCase()
239+
: undefined;
240+
const devCredentialFunctions = [
240241
createDefaultAzureCliCredential,
241242
createDefaultAzurePowershellCredential,
242243
createDefaultAzureDeveloperCliCredential,
243244
];
245+
const prodCredentialFunctions = [
246+
createEnvironmentCredential,
247+
createDefaultWorkloadIdentityCredential,
248+
createDefaultManagedIdentityCredential,
249+
];
250+
let credentialFunctions = [];
251+
// If AZURE_TOKEN_CREDENTIALS is set, use it to determine which credentials to use.
252+
// The value of AZURE_TOKEN_CREDENTIALS should be either "dev" or "prod".
253+
if (azureTokenCredentials) {
254+
switch (azureTokenCredentials) {
255+
case "dev":
256+
// If AZURE_TOKEN_CREDENTIALS is set to "dev", use the developer tool-based credential chain.
257+
credentialFunctions = devCredentialFunctions;
258+
break;
259+
case "prod":
260+
// If AZURE_TOKEN_CREDENTIALS is set to "prod", use the production credential chain.
261+
credentialFunctions = prodCredentialFunctions;
262+
break;
263+
default: {
264+
// If AZURE_TOKEN_CREDENTIALS is set to an unsupported value, throw an error.
265+
// We will throw an error here to prevent the creation of the DefaultAzureCredential.
266+
const errorMessage = `Invalid value for AZURE_TOKEN_CREDENTIALS = ${process.env.AZURE_TOKEN_CREDENTIALS}. Valid values are 'prod' or 'dev'.`;
267+
logger.warning(errorMessage);
268+
throw new Error(errorMessage);
269+
}
270+
}
271+
} else {
272+
// If AZURE_TOKEN_CREDENTIALS is not set, use the default credential chain.
273+
credentialFunctions = [...prodCredentialFunctions, ...devCredentialFunctions];
274+
}
244275

245-
// DefaultCredential constructors should not throw, instead throwing on getToken() which is handled by ChainedTokenCredential.
246-
276+
// Errors from individual credentials should not be thrown in the DefaultAzureCredential constructor, instead throwing on getToken() which is handled by ChainedTokenCredential.
247277
// When adding new credentials to the default chain, consider:
248278
// 1. Making the constructor parameters required and explicit
249279
// 2. Validating any required parameters in the factory function
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
import { DefaultAzureCredential } from "../../../src/index.js";
4+
import { describe, it, expect, vi, afterEach } from "vitest";
5+
6+
describe("DefaultAzureCredential", () => {
7+
afterEach(() => {
8+
vi.restoreAllMocks();
9+
});
10+
11+
it("should create a DefaultAzureCredential instance", () => {
12+
const credential = new DefaultAzureCredential();
13+
expect(credential).toBeInstanceOf(DefaultAzureCredential);
14+
});
15+
it("should throw an error if AZURE_TOKEN_CREDENTIALS is set to an unsupported value", () => {
16+
process.env.AZURE_TOKEN_CREDENTIALS = "randomValue";
17+
expect(() => new DefaultAzureCredential()).toThrowError(
18+
"Invalid value for AZURE_TOKEN_CREDENTIALS = randomValue. Valid values are 'prod' or 'dev'.",
19+
);
20+
});
21+
it("should not throw an error if AZURE_TOKEN_CREDENTIALS is set to a supported value", () => {
22+
process.env.AZURE_TOKEN_CREDENTIALS = "prod";
23+
expect(() => new DefaultAzureCredential()).not.toThrowError();
24+
process.env.AZURE_TOKEN_CREDENTIALS = "dev";
25+
expect(() => new DefaultAzureCredential()).not.toThrowError();
26+
});
27+
});

0 commit comments

Comments
 (0)