@azure/identity 4.4.1 → 4.5.0-alpha.20240813.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/README.md +22 -1
  2. package/dist/index.js +169 -85
  3. package/dist/index.js.map +1 -1
  4. package/dist-esm/src/client/identityClient.js +1 -2
  5. package/dist-esm/src/client/identityClient.js.map +1 -1
  6. package/dist-esm/src/constants.js +1 -1
  7. package/dist-esm/src/constants.js.map +1 -1
  8. package/dist-esm/src/credentials/azurePipelinesCredential.js +14 -5
  9. package/dist-esm/src/credentials/azurePipelinesCredential.js.map +1 -1
  10. package/dist-esm/src/credentials/azurePowerShellCredential.js +30 -13
  11. package/dist-esm/src/credentials/azurePowerShellCredential.js.map +1 -1
  12. package/dist-esm/src/credentials/clientAssertionCredential.js +9 -2
  13. package/dist-esm/src/credentials/clientAssertionCredential.js.map +1 -1
  14. package/dist-esm/src/credentials/clientCertificateCredential.js +35 -27
  15. package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
  16. package/dist-esm/src/credentials/clientSecretCredential.js +9 -2
  17. package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
  18. package/dist-esm/src/credentials/deviceCodeCredential.js +1 -1
  19. package/dist-esm/src/credentials/deviceCodeCredential.js.map +1 -1
  20. package/dist-esm/src/credentials/deviceCodeCredentialOptions.js.map +1 -1
  21. package/dist-esm/src/credentials/environmentCredential.js +11 -1
  22. package/dist-esm/src/credentials/environmentCredential.js.map +1 -1
  23. package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js.map +1 -1
  24. package/dist-esm/src/credentials/interactiveBrowserCredential.js +1 -1
  25. package/dist-esm/src/credentials/interactiveBrowserCredential.js.map +1 -1
  26. package/dist-esm/src/credentials/interactiveBrowserCredentialOptions.js.map +1 -1
  27. package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js +6 -5
  28. package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js.map +1 -1
  29. package/dist-esm/src/credentials/onBehalfOfCredential.js +16 -9
  30. package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -1
  31. package/dist-esm/src/credentials/usernamePasswordCredential.js +13 -3
  32. package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
  33. package/dist-esm/src/credentials/workloadIdentityCredential.js +16 -6
  34. package/dist-esm/src/credentials/workloadIdentityCredential.js.map +1 -1
  35. package/dist-esm/src/errors.js +12 -7
  36. package/dist-esm/src/errors.js.map +1 -1
  37. package/dist-esm/src/msal/browserFlows/flows.js.map +1 -0
  38. package/dist-esm/src/msal/browserFlows/msalBrowserCommon.js.map +1 -1
  39. package/dist-esm/src/msal/nodeFlows/msalClient.js +8 -1
  40. package/dist-esm/src/msal/nodeFlows/msalClient.js.map +1 -1
  41. package/package.json +4 -4
  42. package/types/identity.d.ts +26 -8
  43. package/dist-esm/src/msal/flows.js.map +0 -1
  44. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +0 -47
  45. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +0 -1
  46. package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js +0 -42
  47. package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js.map +0 -1
  48. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +0 -112
  49. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +0 -1
  50. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js +0 -33
  51. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +0 -1
  52. package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js +0 -35
  53. package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js.map +0 -1
  54. package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js +0 -323
  55. package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js.map +0 -1
  56. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +0 -58
  57. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +0 -1
  58. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +0 -113
  59. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +0 -1
  60. package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js +0 -33
  61. package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js.map +0 -1
  62. /package/dist-esm/src/msal/{flows.js → browserFlows/flows.js} +0 -0
package/README.md CHANGED
@@ -213,7 +213,7 @@ For examples of how to use managed identity for authentication, see [the example
213
213
 
214
214
  ## Cloud configuration
215
215
 
216
- Credentials default to authenticating to the Microsoft Entra endpoint for Azure Public Cloud. To access resources in other clouds, such as Azure Government or a private cloud, configure credentials with the `authorityHost` argument in the constructor. The `AzureAuthorityHosts` interface defines authorities for well-known clouds. For the US Government cloud, you could instantiate a credential this way:
216
+ Credentials default to authenticating to the Microsoft Entra endpoint for Azure Public Cloud. To access resources in other clouds, such as Azure Government or a private cloud, configure credentials with the `authorityHost` argument in the constructor. The [`AzureAuthorityHosts`][authority_hosts] enum defines authorities for well-known clouds. For the US Government cloud, you could instantiate a credential this way:
217
217
 
218
218
  ```typescript
219
219
  import { AzureAuthorityHosts, ClientSecretCredential } from "@azure/identity";
@@ -227,6 +227,26 @@ const credential = new ClientSecretCredential(
227
227
  );
228
228
  ```
229
229
 
230
+ As an alternative to specifying the `authorityHost` argument, you can also set the `AZURE_AUTHORITY_HOST` environment variable to the URL of your cloud's authority. This approach is useful when configuring multiple credentials to authenticate to the same cloud or when the deployed environment needs to define the target cloud:
231
+
232
+ ```sh
233
+ AZURE_AUTHORITY_HOST=https://login.partner.microsoftonline.cn
234
+ ```
235
+
236
+ The `AzureAuthorityHosts` enum defines authorities for well-known clouds for your convenience; however, if the authority for your cloud isn't listed in `AzureAuthorityHosts`, you may pass any valid authority URL as a string argument. For example:
237
+
238
+ ```typescript
239
+ import { AzureAuthorityHosts, ClientSecretCredential } from "@azure/identity";
240
+ const credential = new ClientSecretCredential(
241
+ "<YOUR_TENANT_ID>",
242
+ "<YOUR_CLIENT_ID>",
243
+ "<YOUR_CLIENT_SECRET>",
244
+ {
245
+ authorityHost: "https://login.partner.microsoftonline.cn",
246
+ }
247
+ );
248
+ ```
249
+
230
250
  Not all credentials require this configuration. Credentials that authenticate through a development tool, such as `AzureCliCredential`, use that tool's configuration. Similarly, `VisualStudioCodeCredential` accepts an `authorityHost` argument but defaults to the `authorityHost` matching Visual Studio Code's **Azure: Cloud** setting.
231
251
 
232
252
  ## Credential classes
@@ -369,5 +389,6 @@ If you'd like to contribute to this library, please read the [contributing guide
369
389
  [defaultauthflow_image]: https://raw.githubusercontent.com/Azure/azure-sdk-for-js/main/sdk/identity/identity/images/mermaidjs/DefaultAzureCredentialAuthFlow.svg
370
390
  [azure_identity_broker]: https://www.npmjs.com/package/@azure/identity-broker
371
391
  [azure_identity_broker_readme]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity-broker
392
+ [authority_hosts]: https://learn.microsoft.com/javascript/api/@azure/identity/azureauthorityhosts
372
393
 
373
394
  ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js%2Fsdk%2Fidentity%2Fidentity%2FREADME.png)
package/dist/index.js CHANGED
@@ -6,18 +6,18 @@ var logger$m = require('@azure/logger');
6
6
  var coreClient = require('@azure/core-client');
7
7
  var coreUtil = require('@azure/core-util');
8
8
  var coreRestPipeline = require('@azure/core-rest-pipeline');
9
- var abortController = require('@azure/abort-controller');
10
9
  var coreTracing = require('@azure/core-tracing');
11
10
  var fs = require('fs');
12
11
  var os = require('os');
13
12
  var path = require('path');
13
+ var abortController = require('@azure/abort-controller');
14
14
  var msalCommon = require('@azure/msal-node');
15
15
  var open = require('open');
16
16
  var promises = require('fs/promises');
17
17
  var child_process = require('child_process');
18
18
  var crypto = require('crypto');
19
- var promises$1 = require('node:fs/promises');
20
19
  var node_crypto = require('node:crypto');
20
+ var promises$1 = require('node:fs/promises');
21
21
 
22
22
  function _interopNamespaceDefault(e) {
23
23
  var n = Object.create(null);
@@ -44,7 +44,7 @@ var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_proce
44
44
  /**
45
45
  * Current version of the `@azure/identity` package.
46
46
  */
47
- const SDK_VERSION = `4.4.1`;
47
+ const SDK_VERSION = `4.5.0-beta.2`;
48
48
  /**
49
49
  * The default client ID for authentication
50
50
  * @internal
@@ -289,8 +289,9 @@ const CredentialUnavailableErrorName = "CredentialUnavailableError";
289
289
  * an error that should halt the chain, it's caught and the chain continues
290
290
  */
291
291
  class CredentialUnavailableError extends Error {
292
- constructor(message) {
293
- super(message);
292
+ constructor(message, options) {
293
+ // @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
294
+ super(message, options);
294
295
  this.name = CredentialUnavailableErrorName;
295
296
  }
296
297
  }
@@ -305,7 +306,7 @@ const AuthenticationErrorName = "AuthenticationError";
305
306
  */
306
307
  class AuthenticationError extends Error {
307
308
  // eslint-disable-next-line @typescript-eslint/ban-types
308
- constructor(statusCode, errorBody) {
309
+ constructor(statusCode, errorBody, options) {
309
310
  let errorResponse = {
310
311
  error: "unknown",
311
312
  errorDescription: "An unknown error occurred and no additional details are available.",
@@ -323,8 +324,8 @@ class AuthenticationError extends Error {
323
324
  catch (e) {
324
325
  if (statusCode === 400) {
325
326
  errorResponse = {
326
- error: "authority_not_found",
327
- errorDescription: "The specified authority URL was not found.",
327
+ error: "invalid_request",
328
+ errorDescription: `The service indicated that the request was invalid.\n\n${errorBody}`,
328
329
  };
329
330
  }
330
331
  else {
@@ -341,7 +342,9 @@ class AuthenticationError extends Error {
341
342
  errorDescription: "An unknown error occurred and no additional details are available.",
342
343
  };
343
344
  }
344
- super(`${errorResponse.error} Status code: ${statusCode}\nMore details:\n${errorResponse.errorDescription}`);
345
+ super(`${errorResponse.error} Status code: ${statusCode}\nMore details:\n${errorResponse.errorDescription},`,
346
+ // @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
347
+ options);
345
348
  this.statusCode = statusCode;
346
349
  this.errorResponse = errorResponse;
347
350
  // Ensure that this type reports the correct name
@@ -384,7 +387,9 @@ class AuthenticationRequiredError extends Error {
384
387
  * Optional parameters. A message can be specified. The {@link GetTokenOptions} of the request can also be specified to more easily associate the error with the received parameters.
385
388
  */
386
389
  options) {
387
- super(options.message);
390
+ super(options.message,
391
+ // @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
392
+ options.cause ? { cause: options.cause } : undefined);
388
393
  this.scopes = options.scopes;
389
394
  this.getTokenOptions = options.getTokenOptions;
390
395
  this.name = "AuthenticationRequiredError";
@@ -674,7 +679,7 @@ class IdentityClient extends coreClient.ServiceClient {
674
679
  // Here is a custom layer that allows us to abort requests that go through MSAL,
675
680
  // since MSAL doesn't allow us to pass options all the way through.
676
681
  generateAbortSignal(correlationId) {
677
- const controller = new abortController.AbortController();
682
+ const controller = new AbortController();
678
683
  const controllers = this.abortControllers.get(correlationId) || [];
679
684
  controllers.push(controller);
680
685
  this.abortControllers.set(correlationId, controllers);
@@ -682,7 +687,7 @@ class IdentityClient extends coreClient.ServiceClient {
682
687
  controller.signal.onabort = (...params) => {
683
688
  this.abortControllers.set(correlationId, undefined);
684
689
  if (existingOnAbort) {
685
- existingOnAbort(...params);
690
+ existingOnAbort.apply(controller.signal, params);
686
691
  }
687
692
  };
688
693
  return controller.signal;
@@ -1524,6 +1529,10 @@ function calculateRegionalAuthority(regionalAuthority) {
1524
1529
 
1525
1530
  // Copyright (c) Microsoft Corporation.
1526
1531
  // Licensed under the MIT license.
1532
+ /**
1533
+ * The default logger used if no logger was passed in by the credential.
1534
+ */
1535
+ const msalLogger = credentialLogger("MsalClient");
1527
1536
  /**
1528
1537
  * A call to open(), but mockable
1529
1538
  * @internal
@@ -1531,13 +1540,6 @@ function calculateRegionalAuthority(regionalAuthority) {
1531
1540
  const interactiveBrowserMockable = {
1532
1541
  open,
1533
1542
  };
1534
-
1535
- // Copyright (c) Microsoft Corporation.
1536
- // Licensed under the MIT license.
1537
- /**
1538
- * The default logger used if no logger was passed in by the credential.
1539
- */
1540
- const msalLogger = credentialLogger("MsalClient");
1541
1543
  /**
1542
1544
  * Generates the configuration for MSAL (Microsoft Authentication Library).
1543
1545
  *
@@ -1983,8 +1985,14 @@ class ClientAssertionCredential {
1983
1985
  * @param options - Options for configuring the client which makes the authentication request.
1984
1986
  */
1985
1987
  constructor(tenantId, clientId, getAssertion, options = {}) {
1986
- if (!tenantId || !clientId || !getAssertion) {
1987
- throw new Error("ClientAssertionCredential: tenantId, clientId, and clientAssertion are required parameters.");
1988
+ if (!tenantId) {
1989
+ throw new CredentialUnavailableError("ClientAssertionCredential: tenantId is a required parameter.");
1990
+ }
1991
+ if (!clientId) {
1992
+ throw new CredentialUnavailableError("ClientAssertionCredential: clientId is a required parameter.");
1993
+ }
1994
+ if (!getAssertion) {
1995
+ throw new CredentialUnavailableError("ClientAssertionCredential: clientAssertion is a required parameter.");
1988
1996
  }
1989
1997
  this.tenantId = tenantId;
1990
1998
  this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
@@ -2059,10 +2067,20 @@ class WorkloadIdentityCredential {
2059
2067
  if (tenantId) {
2060
2068
  checkTenantId(logger$g, tenantId);
2061
2069
  }
2062
- if (clientId && tenantId && this.federatedTokenFilePath) {
2063
- logger$g.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
2064
- this.client = new ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), options);
2070
+ if (!clientId) {
2071
+ throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
2072
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
2073
+ }
2074
+ if (!tenantId) {
2075
+ throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
2076
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
2077
+ }
2078
+ if (!this.federatedTokenFilePath) {
2079
+ throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_FEDERATED_TOKEN_FILE".
2080
+ See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
2065
2081
  }
2082
+ logger$g.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
2083
+ this.client = new ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), options);
2066
2084
  }
2067
2085
  /**
2068
2086
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -2078,7 +2096,7 @@ class WorkloadIdentityCredential {
2078
2096
  In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
2079
2097
  "AZURE_TENANT_ID",
2080
2098
  "AZURE_CLIENT_ID",
2081
- "AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot `;
2099
+ "AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;
2082
2100
  logger$g.info(errorMessage);
2083
2101
  throw new CredentialUnavailableError(errorMessage);
2084
2102
  }
@@ -2217,6 +2235,7 @@ class MsalMsiProvider {
2217
2235
  // We will continue to implement these features in the Identity library.
2218
2236
  const identitySource = this.managedIdentityApp.getManagedIdentitySource();
2219
2237
  const isImdsMsi = identitySource === "DefaultToImds" || identitySource === "Imds"; // Neither actually checks that IMDS endpoint is available, just that it's the source the MSAL _would_ try to use.
2238
+ logger$e.getToken.info(`MSAL Identity source: ${identitySource}`);
2220
2239
  if (isTokenExchangeMsi) {
2221
2240
  // In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
2222
2241
  logger$e.getToken.info("Using the token exchange managed identity.");
@@ -2228,7 +2247,7 @@ class MsalMsiProvider {
2228
2247
  resourceId: this.resourceId,
2229
2248
  });
2230
2249
  if (result === null) {
2231
- throw new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2250
+ throw new CredentialUnavailableError("Attempted to use the token exchange managed identity, but received a null response.");
2232
2251
  }
2233
2252
  return result;
2234
2253
  }
@@ -2244,7 +2263,7 @@ class MsalMsiProvider {
2244
2263
  resourceId: this.resourceId,
2245
2264
  });
2246
2265
  if (!isAvailable) {
2247
- throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is not available.`);
2266
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Attempted to use the IMDS endpoint, but it is not available.`);
2248
2267
  }
2249
2268
  }
2250
2269
  // If we got this far, it means:
@@ -2270,9 +2289,9 @@ class MsalMsiProvider {
2270
2289
  throw err;
2271
2290
  }
2272
2291
  if (isNetworkError(err)) {
2273
- throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`);
2292
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err });
2274
2293
  }
2275
- throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`);
2294
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err });
2276
2295
  }
2277
2296
  });
2278
2297
  }
@@ -2289,7 +2308,7 @@ class MsalMsiProvider {
2289
2308
  });
2290
2309
  };
2291
2310
  if (!msalToken) {
2292
- throw createError("No response");
2311
+ throw createError("No response.");
2293
2312
  }
2294
2313
  if (!msalToken.expiresOn) {
2295
2314
  throw createError(`Response had no "expiresOn" property.`);
@@ -2848,27 +2867,44 @@ class AzurePowerShellCredential {
2848
2867
  commandStack.shift();
2849
2868
  continue;
2850
2869
  }
2851
- let tenantSection = "";
2852
- if (tenantId) {
2853
- tenantSection = `-TenantId "${tenantId}"`;
2854
- }
2855
2870
  const results = await runCommands([
2856
2871
  [
2857
2872
  powerShellCommand,
2858
2873
  "-NoProfile",
2859
2874
  "-NonInteractive",
2860
2875
  "-Command",
2861
- "Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru",
2862
- ],
2863
- [
2864
- powerShellCommand,
2865
- "-NoProfile",
2866
- "-NonInteractive",
2867
- "-Command",
2868
- `Get-AzAccessToken ${tenantSection} -ResourceUrl "${resource}" | ConvertTo-Json`,
2876
+ `
2877
+ $tenantId = "${tenantId !== null && tenantId !== void 0 ? tenantId : ""}"
2878
+ $m = Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru
2879
+ $useSecureString = $m.Version -ge [version]'2.17.0'
2880
+
2881
+ $params = @{
2882
+ ResourceUrl = "${resource}"
2883
+ }
2884
+
2885
+ if ($tenantId.Length -gt 0) {
2886
+ $params["TenantId"] = $tenantId
2887
+ }
2888
+
2889
+ if ($useSecureString) {
2890
+ $params["AsSecureString"] = $true
2891
+ }
2892
+
2893
+ $token = Get-AzAccessToken @params
2894
+
2895
+ $result = New-Object -TypeName PSObject
2896
+ $result | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn
2897
+ if ($useSecureString) {
2898
+ $result | Add-Member -MemberType NoteProperty -Name Token -Value (ConvertFrom-SecureString -AsPlainText $token.Token)
2899
+ } else {
2900
+ $result | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token
2901
+ }
2902
+
2903
+ Write-Output (ConvertTo-Json $result)
2904
+ `,
2869
2905
  ],
2870
2906
  ]);
2871
- const result = results[1];
2907
+ const result = results[0];
2872
2908
  return parseJsonToken(result);
2873
2909
  }
2874
2910
  throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
@@ -3080,7 +3116,8 @@ class ClientCertificateCredential {
3080
3116
  });
3081
3117
  }
3082
3118
  async buildClientCertificate() {
3083
- const parts = await this.parseCertificate();
3119
+ var _a;
3120
+ const parts = await parseCertificate(this.certificateConfiguration, (_a = this.sendCertificateChain) !== null && _a !== void 0 ? _a : false);
3084
3121
  let privateKey;
3085
3122
  if (this.certificateConfiguration.certificatePassword !== undefined) {
3086
3123
  privateKey = crypto.createPrivateKey({
@@ -3103,34 +3140,41 @@ class ClientCertificateCredential {
3103
3140
  x5c: parts.x5c,
3104
3141
  };
3105
3142
  }
3106
- async parseCertificate() {
3107
- const certificate = this.certificateConfiguration.certificate;
3108
- const certificatePath = this.certificateConfiguration.certificatePath;
3109
- const certificateContents = certificate || (await promises.readFile(certificatePath, "utf8"));
3110
- const x5c = this.sendCertificateChain ? certificateContents : undefined;
3111
- const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
3112
- const publicKeys = [];
3113
- // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
3114
- let match;
3115
- do {
3116
- match = certificatePattern.exec(certificateContents);
3117
- if (match) {
3118
- publicKeys.push(match[3]);
3119
- }
3120
- } while (match);
3121
- if (publicKeys.length === 0) {
3122
- throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
3143
+ }
3144
+ /**
3145
+ * Parses a certificate into its relevant parts
3146
+ *
3147
+ * @param certificateConfiguration - The certificate contents or path to the certificate
3148
+ * @param sendCertificateChain - true if the entire certificate chain should be sent for SNI, false otherwise
3149
+ * @returns The parsed certificate parts and the certificate contents
3150
+ */
3151
+ async function parseCertificate(certificateConfiguration, sendCertificateChain) {
3152
+ const certificate = certificateConfiguration.certificate;
3153
+ const certificatePath = certificateConfiguration.certificatePath;
3154
+ const certificateContents = certificate || (await promises.readFile(certificatePath, "utf8"));
3155
+ const x5c = sendCertificateChain ? certificateContents : undefined;
3156
+ const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
3157
+ const publicKeys = [];
3158
+ // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
3159
+ let match;
3160
+ do {
3161
+ match = certificatePattern.exec(certificateContents);
3162
+ if (match) {
3163
+ publicKeys.push(match[3]);
3123
3164
  }
3124
- const thumbprint = crypto.createHash("sha1")
3125
- .update(Buffer.from(publicKeys[0], "base64"))
3126
- .digest("hex")
3127
- .toUpperCase();
3128
- return {
3129
- certificateContents,
3130
- thumbprint,
3131
- x5c,
3132
- };
3133
- }
3165
+ } while (match);
3166
+ if (publicKeys.length === 0) {
3167
+ throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
3168
+ }
3169
+ const thumbprint = crypto.createHash("sha1")
3170
+ .update(Buffer.from(publicKeys[0], "base64"))
3171
+ .digest("hex")
3172
+ .toUpperCase();
3173
+ return {
3174
+ certificateContents,
3175
+ thumbprint,
3176
+ x5c,
3177
+ };
3134
3178
  }
3135
3179
 
3136
3180
  // Copyright (c) Microsoft Corporation.
@@ -3156,8 +3200,14 @@ class ClientSecretCredential {
3156
3200
  * @param options - Options for configuring the client which makes the authentication request.
3157
3201
  */
3158
3202
  constructor(tenantId, clientId, clientSecret, options = {}) {
3159
- if (!tenantId || !clientId || !clientSecret) {
3160
- throw new Error("ClientSecretCredential: tenantId, clientId, and clientSecret are required parameters. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
3203
+ if (!tenantId) {
3204
+ throw new CredentialUnavailableError("ClientSecretCredential: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
3205
+ }
3206
+ if (!clientId) {
3207
+ throw new CredentialUnavailableError("ClientSecretCredential: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
3208
+ }
3209
+ if (!clientSecret) {
3210
+ throw new CredentialUnavailableError("ClientSecretCredential: clientSecret is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
3161
3211
  }
3162
3212
  this.clientSecret = clientSecret;
3163
3213
  this.tenantId = tenantId;
@@ -3203,8 +3253,17 @@ class UsernamePasswordCredential {
3203
3253
  * @param options - Options for configuring the client which makes the authentication request.
3204
3254
  */
3205
3255
  constructor(tenantId, clientId, username, password, options = {}) {
3206
- if (!tenantId || !clientId || !username || !password) {
3207
- throw new Error("UsernamePasswordCredential: tenantId, clientId, username and password are required parameters. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
3256
+ if (!tenantId) {
3257
+ throw new CredentialUnavailableError("UsernamePasswordCredential: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
3258
+ }
3259
+ if (!clientId) {
3260
+ throw new CredentialUnavailableError("UsernamePasswordCredential: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
3261
+ }
3262
+ if (!username) {
3263
+ throw new CredentialUnavailableError("UsernamePasswordCredential: username is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
3264
+ }
3265
+ if (!password) {
3266
+ throw new CredentialUnavailableError("UsernamePasswordCredential: password is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
3208
3267
  }
3209
3268
  this.tenantId = tenantId;
3210
3269
  this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
@@ -3251,6 +3310,7 @@ const AllSupportedEnvironmentVariables = [
3251
3310
  "AZURE_USERNAME",
3252
3311
  "AZURE_PASSWORD",
3253
3312
  "AZURE_ADDITIONALLY_ALLOWED_TENANTS",
3313
+ "AZURE_CLIENT_SEND_CERTIFICATE_CHAIN",
3254
3314
  ];
3255
3315
  function getAdditionallyAllowedTenants() {
3256
3316
  var _a;
@@ -3259,6 +3319,13 @@ function getAdditionallyAllowedTenants() {
3259
3319
  }
3260
3320
  const credentialName$2 = "EnvironmentCredential";
3261
3321
  const logger$6 = credentialLogger(credentialName$2);
3322
+ function getSendCertificateChain() {
3323
+ var _a;
3324
+ const sendCertificateChain = ((_a = process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN) !== null && _a !== void 0 ? _a : "").toLowerCase();
3325
+ const result = sendCertificateChain === "true" || sendCertificateChain === "1";
3326
+ logger$6.verbose(`AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: ${process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN}; sendCertificateChain: ${result}`);
3327
+ return result;
3328
+ }
3262
3329
  /**
3263
3330
  * Enables authentication to Microsoft Entra ID using a client secret or certificate, or as a user
3264
3331
  * with a username and password.
@@ -3278,6 +3345,7 @@ class EnvironmentCredential {
3278
3345
  * - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
3279
3346
  * - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
3280
3347
  * - `AZURE_CLIENT_CERTIFICATE_PASSWORD`: (optional) password for the certificate file.
3348
+ * - `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN`: (optional) indicates that the certificate chain should be set in x5c header to support subject name / issuer based authentication.
3281
3349
  *
3282
3350
  * Alternatively, users can provide environment variables for username and password authentication:
3283
3351
  * - `AZURE_USERNAME`: Username to authenticate with.
@@ -3295,7 +3363,8 @@ class EnvironmentCredential {
3295
3363
  logger$6.info(`Found the following environment variables: ${assigned}`);
3296
3364
  const tenantId = process.env.AZURE_TENANT_ID, clientId = process.env.AZURE_CLIENT_ID, clientSecret = process.env.AZURE_CLIENT_SECRET;
3297
3365
  const additionallyAllowedTenantIds = getAdditionallyAllowedTenants();
3298
- const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds });
3366
+ const sendCertificateChain = getSendCertificateChain();
3367
+ const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds, sendCertificateChain });
3299
3368
  if (tenantId) {
3300
3369
  checkTenantId(logger$6, tenantId);
3301
3370
  }
@@ -3556,7 +3625,7 @@ class InteractiveBrowserCredential {
3556
3625
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
3557
3626
  * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
3558
3627
  *
3559
- * If the token can't be retrieved silently, this method will require user interaction to retrieve the token.
3628
+ * If the token can't be retrieved silently, this method will always generate a challenge for the user.
3560
3629
  *
3561
3630
  * On Node.js, this credential has [Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) enabled by default.
3562
3631
  * PKCE is a security feature that mitigates authentication code interception attacks.
@@ -3642,7 +3711,7 @@ class DeviceCodeCredential {
3642
3711
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
3643
3712
  * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
3644
3713
  *
3645
- * If the token can't be retrieved silently, this method will require user interaction to retrieve the token.
3714
+ * If the token can't be retrieved silently, this method will always generate a challenge for the user.
3646
3715
  *
3647
3716
  * @param scopes - The list of scopes for which the token will have access.
3648
3717
  * @param options - The options used to configure any requests this
@@ -3676,8 +3745,17 @@ class AzurePipelinesCredential {
3676
3745
  * @param options - The identity client options to use for authentication.
3677
3746
  */
3678
3747
  constructor(tenantId, clientId, serviceConnectionId, systemAccessToken, options) {
3679
- if (!clientId || !tenantId || !serviceConnectionId || !systemAccessToken) {
3680
- throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. tenantId, clientId, serviceConnectionId, and systemAccessToken are required parameters.`);
3748
+ if (!clientId) {
3749
+ throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. clientId is a required parameter.`);
3750
+ }
3751
+ if (!tenantId) {
3752
+ throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. tenantId is a required parameter.`);
3753
+ }
3754
+ if (!serviceConnectionId) {
3755
+ throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. serviceConnectionId is a required parameter.`);
3756
+ }
3757
+ if (!systemAccessToken) {
3758
+ throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. systemAccessToken is a required parameter.`);
3681
3759
  }
3682
3760
  this.identityClient = new IdentityClient(options);
3683
3761
  checkTenantId(logger$2, tenantId);
@@ -3839,11 +3917,17 @@ class OnBehalfOfCredential {
3839
3917
  const { certificatePath, sendCertificateChain } = options;
3840
3918
  const { getAssertion } = options;
3841
3919
  const { tenantId, clientId, userAssertionToken, additionallyAllowedTenants: additionallyAllowedTenantIds, } = options;
3842
- if (!tenantId ||
3843
- !clientId ||
3844
- !(clientSecret || certificatePath || getAssertion) ||
3845
- !userAssertionToken) {
3846
- throw new Error(`${credentialName}: tenantId, clientId, clientSecret (or certificatePath or getAssertion) and userAssertionToken are required parameters.`);
3920
+ if (!tenantId) {
3921
+ throw new CredentialUnavailableError(`${credentialName}: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
3922
+ }
3923
+ if (!clientId) {
3924
+ throw new CredentialUnavailableError(`${credentialName}: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
3925
+ }
3926
+ if (!clientSecret && !certificatePath && !getAssertion) {
3927
+ throw new CredentialUnavailableError(`${credentialName}: You must provide one of clientSecret, certificatePath, or a getAssertion callback but none were provided. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
3928
+ }
3929
+ if (!userAssertionToken) {
3930
+ throw new CredentialUnavailableError(`${credentialName}: userAssertionToken is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
3847
3931
  }
3848
3932
  this.certificatePath = certificatePath;
3849
3933
  this.clientSecret = clientSecret;