@azure/identity 4.4.0 → 4.5.0-alpha.20240813.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +22 -1
  2. package/dist/index.js +441 -812
  3. package/dist/index.js.map +1 -1
  4. package/dist-esm/src/client/identityClient.js +8 -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 +50 -26
  9. package/dist-esm/src/credentials/azurePipelinesCredential.js.map +1 -1
  10. package/dist-esm/src/credentials/azurePowerShellCredential.js +63 -19
  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/imdsRetryPolicy.js +37 -0
  28. package/dist-esm/src/credentials/managedIdentityCredential/imdsRetryPolicy.js.map +1 -0
  29. package/dist-esm/src/credentials/managedIdentityCredential/index.js +6 -2
  30. package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
  31. package/dist-esm/src/credentials/managedIdentityCredential/legacyMsiProvider.js +1 -1
  32. package/dist-esm/src/credentials/managedIdentityCredential/legacyMsiProvider.js.map +1 -1
  33. package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js +195 -0
  34. package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js.map +1 -0
  35. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +19 -22
  36. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -1
  37. package/dist-esm/src/credentials/onBehalfOfCredential.js +16 -9
  38. package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -1
  39. package/dist-esm/src/credentials/usernamePasswordCredential.js +13 -3
  40. package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
  41. package/dist-esm/src/credentials/workloadIdentityCredential.js +16 -6
  42. package/dist-esm/src/credentials/workloadIdentityCredential.js.map +1 -1
  43. package/dist-esm/src/errors.js +12 -7
  44. package/dist-esm/src/errors.js.map +1 -1
  45. package/dist-esm/src/msal/browserFlows/flows.js.map +1 -0
  46. package/dist-esm/src/msal/browserFlows/msalBrowserCommon.js.map +1 -1
  47. package/dist-esm/src/msal/nodeFlows/msalClient.js +8 -1
  48. package/dist-esm/src/msal/nodeFlows/msalClient.js.map +1 -1
  49. package/package.json +4 -4
  50. package/types/identity.d.ts +26 -8
  51. package/dist-esm/src/msal/flows.js.map +0 -1
  52. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +0 -47
  53. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +0 -1
  54. package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js +0 -42
  55. package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js.map +0 -1
  56. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +0 -112
  57. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +0 -1
  58. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js +0 -33
  59. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +0 -1
  60. package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js +0 -35
  61. package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js.map +0 -1
  62. package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js +0 -323
  63. package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js.map +0 -1
  64. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +0 -58
  65. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +0 -1
  66. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +0 -113
  67. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +0 -1
  68. package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js +0 -33
  69. package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js.map +0 -1
  70. /package/dist-esm/src/msal/{flows.js → browserFlows/flows.js} +0 -0
package/dist/index.js CHANGED
@@ -2,24 +2,22 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var logger$r = require('@azure/logger');
5
+ 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
- var fs$1 = require('node:fs');
16
- var https = require('https');
17
15
  var open = require('open');
18
16
  var promises = require('fs/promises');
19
17
  var child_process = require('child_process');
20
18
  var crypto = require('crypto');
21
- var promises$1 = require('node:fs/promises');
22
19
  var node_crypto = require('node:crypto');
20
+ var promises$1 = require('node:fs/promises');
23
21
 
24
22
  function _interopNamespaceDefault(e) {
25
23
  var n = Object.create(null);
@@ -46,7 +44,7 @@ var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_proce
46
44
  /**
47
45
  * Current version of the `@azure/identity` package.
48
46
  */
49
- const SDK_VERSION = `4.4.0`;
47
+ const SDK_VERSION = `4.5.0-beta.2`;
50
48
  /**
51
49
  * The default client ID for authentication
52
50
  * @internal
@@ -196,7 +194,7 @@ const msalPlugins = {
196
194
  /**
197
195
  * The AzureLogger used for all clients within the identity package
198
196
  */
199
- const logger$q = logger$r.createClientLogger("identity");
197
+ const logger$l = logger$m.createClientLogger("identity");
200
198
  /**
201
199
  * Separates a list of environment variable names into a plain object with two arrays: an array of missing environment variables and another array with assigned environment variables.
202
200
  * @param supportedEnvVars - List of environment variable names
@@ -236,7 +234,7 @@ function formatError(scope, error) {
236
234
  * `[title] => [message]`
237
235
  *
238
236
  */
239
- function credentialLoggerInstance(title, parent, log = logger$q) {
237
+ function credentialLoggerInstance(title, parent, log = logger$l) {
240
238
  const fullTitle = parent ? `${parent.fullTitle} ${title}` : title;
241
239
  function info(message) {
242
240
  log.info(`${fullTitle} =>`, message);
@@ -269,7 +267,7 @@ function credentialLoggerInstance(title, parent, log = logger$q) {
269
267
  * `[title] => getToken() => [message]`
270
268
  *
271
269
  */
272
- function credentialLogger(title, log = logger$q) {
270
+ function credentialLogger(title, log = logger$l) {
273
271
  const credLogger = credentialLoggerInstance(title, undefined, log);
274
272
  return Object.assign(Object.assign({}, credLogger), { parent: log, getToken: credentialLoggerInstance("=> getToken()", credLogger, log) });
275
273
  }
@@ -291,8 +289,9 @@ const CredentialUnavailableErrorName = "CredentialUnavailableError";
291
289
  * an error that should halt the chain, it's caught and the chain continues
292
290
  */
293
291
  class CredentialUnavailableError extends Error {
294
- constructor(message) {
295
- 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);
296
295
  this.name = CredentialUnavailableErrorName;
297
296
  }
298
297
  }
@@ -307,7 +306,7 @@ const AuthenticationErrorName = "AuthenticationError";
307
306
  */
308
307
  class AuthenticationError extends Error {
309
308
  // eslint-disable-next-line @typescript-eslint/ban-types
310
- constructor(statusCode, errorBody) {
309
+ constructor(statusCode, errorBody, options) {
311
310
  let errorResponse = {
312
311
  error: "unknown",
313
312
  errorDescription: "An unknown error occurred and no additional details are available.",
@@ -325,8 +324,8 @@ class AuthenticationError extends Error {
325
324
  catch (e) {
326
325
  if (statusCode === 400) {
327
326
  errorResponse = {
328
- error: "authority_not_found",
329
- 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}`,
330
329
  };
331
330
  }
332
331
  else {
@@ -343,7 +342,9 @@ class AuthenticationError extends Error {
343
342
  errorDescription: "An unknown error occurred and no additional details are available.",
344
343
  };
345
344
  }
346
- 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);
347
348
  this.statusCode = statusCode;
348
349
  this.errorResponse = errorResponse;
349
350
  // Ensure that this type reports the correct name
@@ -386,7 +387,9 @@ class AuthenticationRequiredError extends Error {
386
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.
387
388
  */
388
389
  options) {
389
- 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);
390
393
  this.scopes = options.scopes;
391
394
  this.getTokenOptions = options.getTokenOptions;
392
395
  this.name = "AuthenticationRequiredError";
@@ -497,8 +500,6 @@ const DefaultScopeSuffix = "/.default";
497
500
  const imdsHost = "http://169.254.169.254";
498
501
  const imdsEndpointPath = "/metadata/identity/oauth2/token";
499
502
  const imdsApiVersion = "2018-02-01";
500
- const azureArcAPIVersion = "2019-11-01";
501
- const azureFabricVersion = "2019-07-01-preview";
502
503
 
503
504
  // Copyright (c) Microsoft Corporation.
504
505
  // Licensed under the MIT license.
@@ -590,14 +591,19 @@ class IdentityClient extends coreClient.ServiceClient {
590
591
  } }, options), { userAgentOptions: {
591
592
  userAgentPrefix,
592
593
  }, baseUri }));
594
+ this.allowInsecureConnection = false;
593
595
  this.authorityHost = baseUri;
594
596
  this.abortControllers = new Map();
595
597
  this.allowLoggingAccountIdentifiers = (_b = options === null || options === void 0 ? void 0 : options.loggingOptions) === null || _b === void 0 ? void 0 : _b.allowLoggingAccountIdentifiers;
596
598
  // used for WorkloadIdentity
597
599
  this.tokenCredentialOptions = Object.assign({}, options);
600
+ // used for ManagedIdentity
601
+ if (options === null || options === void 0 ? void 0 : options.allowInsecureConnection) {
602
+ this.allowInsecureConnection = options.allowInsecureConnection;
603
+ }
598
604
  }
599
605
  async sendTokenRequest(request) {
600
- logger$q.info(`IdentityClient: sending token request to [${request.url}]`);
606
+ logger$l.info(`IdentityClient: sending token request to [${request.url}]`);
601
607
  const response = await this.sendRequest(request);
602
608
  if (response.bodyAsText && (response.status === 200 || response.status === 201)) {
603
609
  const parsedBody = JSON.parse(response.bodyAsText);
@@ -612,12 +618,12 @@ class IdentityClient extends coreClient.ServiceClient {
612
618
  },
613
619
  refreshToken: parsedBody.refresh_token,
614
620
  };
615
- logger$q.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
621
+ logger$l.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
616
622
  return token;
617
623
  }
618
624
  else {
619
625
  const error = new AuthenticationError(response.status, response.bodyAsText);
620
- logger$q.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
626
+ logger$l.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
621
627
  throw error;
622
628
  }
623
629
  }
@@ -625,7 +631,7 @@ class IdentityClient extends coreClient.ServiceClient {
625
631
  if (refreshToken === undefined) {
626
632
  return null;
627
633
  }
628
- logger$q.info(`IdentityClient: refreshing access token with client ID: ${clientId}, scopes: ${scopes} started`);
634
+ logger$l.info(`IdentityClient: refreshing access token with client ID: ${clientId}, scopes: ${scopes} started`);
629
635
  const refreshParams = {
630
636
  grant_type: "refresh_token",
631
637
  client_id: clientId,
@@ -651,7 +657,7 @@ class IdentityClient extends coreClient.ServiceClient {
651
657
  tracingOptions: updatedOptions.tracingOptions,
652
658
  });
653
659
  const response = await this.sendTokenRequest(request);
654
- logger$q.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
660
+ logger$l.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
655
661
  return response;
656
662
  }
657
663
  catch (err) {
@@ -660,11 +666,11 @@ class IdentityClient extends coreClient.ServiceClient {
660
666
  // It's likely that the refresh token has expired, so
661
667
  // return null so that the credential implementation will
662
668
  // initiate the authentication flow again.
663
- logger$q.info(`IdentityClient: interaction required for client ID: ${clientId}`);
669
+ logger$l.info(`IdentityClient: interaction required for client ID: ${clientId}`);
664
670
  return null;
665
671
  }
666
672
  else {
667
- logger$q.warning(`IdentityClient: failed refreshing token for client ID: ${clientId}: ${err}`);
673
+ logger$l.warning(`IdentityClient: failed refreshing token for client ID: ${clientId}: ${err}`);
668
674
  throw err;
669
675
  }
670
676
  }
@@ -673,7 +679,7 @@ class IdentityClient extends coreClient.ServiceClient {
673
679
  // Here is a custom layer that allows us to abort requests that go through MSAL,
674
680
  // since MSAL doesn't allow us to pass options all the way through.
675
681
  generateAbortSignal(correlationId) {
676
- const controller = new abortController.AbortController();
682
+ const controller = new AbortController();
677
683
  const controllers = this.abortControllers.get(correlationId) || [];
678
684
  controllers.push(controller);
679
685
  this.abortControllers.set(correlationId, controllers);
@@ -681,7 +687,7 @@ class IdentityClient extends coreClient.ServiceClient {
681
687
  controller.signal.onabort = (...params) => {
682
688
  this.abortControllers.set(correlationId, undefined);
683
689
  if (existingOnAbort) {
684
- existingOnAbort(...params);
690
+ existingOnAbort.apply(controller.signal, params);
685
691
  }
686
692
  };
687
693
  return controller.signal;
@@ -712,6 +718,7 @@ class IdentityClient extends coreClient.ServiceClient {
712
718
  url,
713
719
  method: "GET",
714
720
  body: options === null || options === void 0 ? void 0 : options.body,
721
+ allowInsecureConnection: this.allowInsecureConnection,
715
722
  headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
716
723
  abortSignal: this.generateAbortSignal(noCorrelationId),
717
724
  });
@@ -729,6 +736,7 @@ class IdentityClient extends coreClient.ServiceClient {
729
736
  method: "POST",
730
737
  body: options === null || options === void 0 ? void 0 : options.body,
731
738
  headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
739
+ allowInsecureConnection: this.allowInsecureConnection,
732
740
  // MSAL doesn't send the correlation ID on the get requests.
733
741
  abortSignal: this.generateAbortSignal(this.getCorrelationId(options)),
734
742
  });
@@ -773,10 +781,10 @@ class IdentityClient extends coreClient.ServiceClient {
773
781
  }
774
782
  const base64Metadata = accessToken.split(".")[1];
775
783
  const { appid, upn, tid, oid } = JSON.parse(Buffer.from(base64Metadata, "base64").toString("utf8"));
776
- logger$q.info(`[Authenticated account] Client ID: ${appid}. Tenant ID: ${tid}. User Principal Name: ${upn || unavailableUpn}. Object ID (user): ${oid}`);
784
+ logger$l.info(`[Authenticated account] Client ID: ${appid}. Tenant ID: ${tid}. User Principal Name: ${upn || unavailableUpn}. Object ID (user): ${oid}`);
777
785
  }
778
786
  catch (e) {
779
- logger$q.warning("allowLoggingAccountIdentifiers was set, but we couldn't log the account information. Error:", e.message);
787
+ logger$l.warning("allowLoggingAccountIdentifiers was set, but we couldn't log the account information. Error:", e.message);
780
788
  }
781
789
  }
782
790
  }
@@ -785,7 +793,7 @@ class IdentityClient extends coreClient.ServiceClient {
785
793
  // Licensed under the MIT license.
786
794
  const CommonTenantId = "common";
787
795
  const AzureAccountClientId = "aebc6443-996d-45c2-90f0-388ff96faa56"; // VSC: 'aebc6443-996d-45c2-90f0-388ff96faa56'
788
- const logger$p = credentialLogger("VisualStudioCodeCredential");
796
+ const logger$k = credentialLogger("VisualStudioCodeCredential");
789
797
  let findCredentials = undefined;
790
798
  const vsCodeCredentialControl = {
791
799
  setVsCodeCredentialFinder(finder) {
@@ -838,7 +846,7 @@ function getPropertyFromVSCode(property) {
838
846
  }
839
847
  }
840
848
  catch (e) {
841
- logger$p.info(`Failed to load the Visual Studio Code configuration file. Error: ${e.message}`);
849
+ logger$k.info(`Failed to load the Visual Studio Code configuration file. Error: ${e.message}`);
842
850
  return;
843
851
  }
844
852
  }
@@ -871,7 +879,7 @@ class VisualStudioCodeCredential {
871
879
  const authorityHost = mapVSCodeAuthorityHosts[this.cloudName];
872
880
  this.identityClient = new IdentityClient(Object.assign({ authorityHost }, options));
873
881
  if (options && options.tenantId) {
874
- checkTenantId(logger$p, options.tenantId);
882
+ checkTenantId(logger$k, options.tenantId);
875
883
  this.tenantId = options.tenantId;
876
884
  }
877
885
  else {
@@ -911,7 +919,7 @@ class VisualStudioCodeCredential {
911
919
  async getToken(scopes, options) {
912
920
  var _a, _b;
913
921
  await this.prepareOnce();
914
- const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds, logger$p) || this.tenantId;
922
+ const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds, logger$k) || this.tenantId;
915
923
  if (findCredentials === undefined) {
916
924
  throw new CredentialUnavailableError([
917
925
  "No implementation of `VisualStudioCodeCredential` is available.",
@@ -925,7 +933,7 @@ class VisualStudioCodeCredential {
925
933
  // Check to make sure the scope we get back is a valid scope
926
934
  if (!scopeString.match(/^[0-9a-zA-Z-.:/]+$/)) {
927
935
  const error = new Error("Invalid scope was specified by the user or calling client");
928
- logger$p.getToken.info(formatError(scopes, error));
936
+ logger$k.getToken.info(formatError(scopes, error));
929
937
  throw error;
930
938
  }
931
939
  if (scopeString.indexOf("offline_access") < 0) {
@@ -945,18 +953,18 @@ class VisualStudioCodeCredential {
945
953
  if (refreshToken) {
946
954
  const tokenResponse = await this.identityClient.refreshAccessToken(tenantId, AzureAccountClientId, scopeString, refreshToken, undefined);
947
955
  if (tokenResponse) {
948
- logger$p.getToken.info(formatSuccess(scopes));
956
+ logger$k.getToken.info(formatSuccess(scopes));
949
957
  return tokenResponse.accessToken;
950
958
  }
951
959
  else {
952
960
  const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Have you connected using the 'Azure Account' extension recently? To troubleshoot, visit https://aka.ms/azsdk/js/identity/vscodecredential/troubleshoot.");
953
- logger$p.getToken.info(formatError(scopes, error));
961
+ logger$k.getToken.info(formatError(scopes, error));
954
962
  throw error;
955
963
  }
956
964
  }
957
965
  else {
958
966
  const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Did you connect using the 'Azure Account' extension? To troubleshoot, visit https://aka.ms/azsdk/js/identity/vscodecredential/troubleshoot.");
959
- logger$p.getToken.info(formatError(scopes, error));
967
+ logger$k.getToken.info(formatError(scopes, error));
960
968
  throw error;
961
969
  }
962
970
  }
@@ -1005,438 +1013,6 @@ function useIdentityPlugin(plugin) {
1005
1013
  plugin(pluginContext);
1006
1014
  }
1007
1015
 
1008
- // Copyright (c) Microsoft Corporation.
1009
- // Licensed under the MIT license.
1010
- const msiName$6 = "ManagedIdentityCredential - CloudShellMSI";
1011
- const logger$o = credentialLogger(msiName$6);
1012
- /**
1013
- * Generates the options used on the request for an access token.
1014
- */
1015
- function prepareRequestOptions$5(scopes, clientId, resourceId) {
1016
- const resource = mapScopesToResource(scopes);
1017
- if (!resource) {
1018
- throw new Error(`${msiName$6}: Multiple scopes are not supported.`);
1019
- }
1020
- const body = {
1021
- resource,
1022
- };
1023
- if (clientId) {
1024
- body.client_id = clientId;
1025
- }
1026
- if (resourceId) {
1027
- body.msi_res_id = resourceId;
1028
- }
1029
- // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
1030
- if (!process.env.MSI_ENDPOINT) {
1031
- throw new Error(`${msiName$6}: Missing environment variable: MSI_ENDPOINT`);
1032
- }
1033
- const params = new URLSearchParams(body);
1034
- return {
1035
- url: process.env.MSI_ENDPOINT,
1036
- method: "POST",
1037
- body: params.toString(),
1038
- headers: coreRestPipeline.createHttpHeaders({
1039
- Accept: "application/json",
1040
- Metadata: "true",
1041
- "Content-Type": "application/x-www-form-urlencoded",
1042
- }),
1043
- };
1044
- }
1045
- /**
1046
- * Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI.
1047
- * Since Azure Managed Identities aren't available in the Azure Cloud Shell, we log a warning for users that try to access cloud shell using user assigned identity.
1048
- */
1049
- const cloudShellMsi = {
1050
- name: "cloudShellMsi",
1051
- async isAvailable({ scopes }) {
1052
- const resource = mapScopesToResource(scopes);
1053
- if (!resource) {
1054
- logger$o.info(`${msiName$6}: Unavailable. Multiple scopes are not supported.`);
1055
- return false;
1056
- }
1057
- const result = Boolean(process.env.MSI_ENDPOINT);
1058
- if (!result) {
1059
- logger$o.info(`${msiName$6}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
1060
- }
1061
- return result;
1062
- },
1063
- async getToken(configuration, getTokenOptions = {}) {
1064
- const { identityClient, scopes, clientId, resourceId } = configuration;
1065
- if (clientId) {
1066
- logger$o.warning(`${msiName$6}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
1067
- }
1068
- if (resourceId) {
1069
- logger$o.warning(`${msiName$6}: user defined managed Identity by resource Id not supported. The argument resourceId might be ignored by the service.`);
1070
- }
1071
- logger$o.info(`${msiName$6}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
1072
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$5(scopes, clientId, resourceId)), {
1073
- // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
1074
- allowInsecureConnection: true }));
1075
- const tokenResponse = await identityClient.sendTokenRequest(request);
1076
- return (tokenResponse && tokenResponse.accessToken) || null;
1077
- },
1078
- };
1079
-
1080
- // Copyright (c) Microsoft Corporation.
1081
- // Licensed under the MIT license.
1082
- const msiName$5 = "ManagedIdentityCredential - AppServiceMSI 2017";
1083
- const logger$n = credentialLogger(msiName$5);
1084
- /**
1085
- * Generates the options used on the request for an access token.
1086
- */
1087
- function prepareRequestOptions$4(scopes, clientId) {
1088
- const resource = mapScopesToResource(scopes);
1089
- if (!resource) {
1090
- throw new Error(`${msiName$5}: Multiple scopes are not supported.`);
1091
- }
1092
- const queryParameters = {
1093
- resource,
1094
- "api-version": "2017-09-01",
1095
- };
1096
- if (clientId) {
1097
- queryParameters.clientid = clientId;
1098
- }
1099
- const query = new URLSearchParams(queryParameters);
1100
- // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
1101
- if (!process.env.MSI_ENDPOINT) {
1102
- throw new Error(`${msiName$5}: Missing environment variable: MSI_ENDPOINT`);
1103
- }
1104
- if (!process.env.MSI_SECRET) {
1105
- throw new Error(`${msiName$5}: Missing environment variable: MSI_SECRET`);
1106
- }
1107
- return {
1108
- url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
1109
- method: "GET",
1110
- headers: coreRestPipeline.createHttpHeaders({
1111
- Accept: "application/json",
1112
- secret: process.env.MSI_SECRET,
1113
- }),
1114
- };
1115
- }
1116
- /**
1117
- * Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI.
1118
- */
1119
- const appServiceMsi2017 = {
1120
- name: "appServiceMsi2017",
1121
- async isAvailable({ scopes }) {
1122
- const resource = mapScopesToResource(scopes);
1123
- if (!resource) {
1124
- logger$n.info(`${msiName$5}: Unavailable. Multiple scopes are not supported.`);
1125
- return false;
1126
- }
1127
- const env = process.env;
1128
- const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
1129
- if (!result) {
1130
- logger$n.info(`${msiName$5}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
1131
- }
1132
- return result;
1133
- },
1134
- async getToken(configuration, getTokenOptions = {}) {
1135
- const { identityClient, scopes, clientId, resourceId } = configuration;
1136
- if (resourceId) {
1137
- logger$n.warning(`${msiName$5}: managed Identity by resource Id is not supported. Argument resourceId might be ignored by the service.`);
1138
- }
1139
- logger$n.info(`${msiName$5}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
1140
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$4(scopes, clientId)), {
1141
- // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
1142
- allowInsecureConnection: true }));
1143
- const tokenResponse = await identityClient.sendTokenRequest(request);
1144
- return (tokenResponse && tokenResponse.accessToken) || null;
1145
- },
1146
- };
1147
-
1148
- // Copyright (c) Microsoft Corporation.
1149
- // Licensed under the MIT license.
1150
- const msiName$4 = "ManagedIdentityCredential - AppServiceMSI 2019";
1151
- const logger$m = credentialLogger(msiName$4);
1152
- /**
1153
- * Generates the options used on the request for an access token.
1154
- */
1155
- function prepareRequestOptions$3(scopes, clientId, resourceId) {
1156
- const resource = mapScopesToResource(scopes);
1157
- if (!resource) {
1158
- throw new Error(`${msiName$4}: Multiple scopes are not supported.`);
1159
- }
1160
- const queryParameters = {
1161
- resource,
1162
- "api-version": "2019-08-01",
1163
- };
1164
- if (clientId) {
1165
- queryParameters.client_id = clientId;
1166
- }
1167
- if (resourceId) {
1168
- queryParameters.mi_res_id = resourceId;
1169
- }
1170
- const query = new URLSearchParams(queryParameters);
1171
- // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
1172
- if (!process.env.IDENTITY_ENDPOINT) {
1173
- throw new Error(`${msiName$4}: Missing environment variable: IDENTITY_ENDPOINT`);
1174
- }
1175
- if (!process.env.IDENTITY_HEADER) {
1176
- throw new Error(`${msiName$4}: Missing environment variable: IDENTITY_HEADER`);
1177
- }
1178
- return {
1179
- url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
1180
- method: "GET",
1181
- headers: coreRestPipeline.createHttpHeaders({
1182
- Accept: "application/json",
1183
- "X-IDENTITY-HEADER": process.env.IDENTITY_HEADER,
1184
- }),
1185
- };
1186
- }
1187
- /**
1188
- * Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI.
1189
- */
1190
- const appServiceMsi2019 = {
1191
- name: "appServiceMsi2019",
1192
- async isAvailable({ scopes }) {
1193
- const resource = mapScopesToResource(scopes);
1194
- if (!resource) {
1195
- logger$m.info(`${msiName$4}: Unavailable. Multiple scopes are not supported.`);
1196
- return false;
1197
- }
1198
- const env = process.env;
1199
- const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER);
1200
- if (!result) {
1201
- logger$m.info(`${msiName$4}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT and IDENTITY_HEADER.`);
1202
- }
1203
- return result;
1204
- },
1205
- async getToken(configuration, getTokenOptions = {}) {
1206
- const { identityClient, scopes, clientId, resourceId } = configuration;
1207
- logger$m.info(`${msiName$4}: Using the endpoint and the secret coming form the environment variables: IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT} and IDENTITY_HEADER=[REDACTED].`);
1208
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes, clientId, resourceId)), {
1209
- // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
1210
- allowInsecureConnection: true }));
1211
- const tokenResponse = await identityClient.sendTokenRequest(request);
1212
- return (tokenResponse && tokenResponse.accessToken) || null;
1213
- },
1214
- };
1215
-
1216
- // Copyright (c) Microsoft Corporation.
1217
- // Licensed under the MIT license.
1218
- const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
1219
- const logger$l = credentialLogger(msiName$3);
1220
- /**
1221
- * Generates the options used on the request for an access token.
1222
- */
1223
- function prepareRequestOptions$2(scopes, clientId, resourceId) {
1224
- const resource = mapScopesToResource(scopes);
1225
- if (!resource) {
1226
- throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
1227
- }
1228
- const queryParameters = {
1229
- resource,
1230
- "api-version": azureArcAPIVersion,
1231
- };
1232
- if (clientId) {
1233
- queryParameters.client_id = clientId;
1234
- }
1235
- if (resourceId) {
1236
- queryParameters.msi_res_id = resourceId;
1237
- }
1238
- // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
1239
- if (!process.env.IDENTITY_ENDPOINT) {
1240
- throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
1241
- }
1242
- const query = new URLSearchParams(queryParameters);
1243
- return coreRestPipeline.createPipelineRequest({
1244
- // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
1245
- url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
1246
- method: "GET",
1247
- headers: coreRestPipeline.createHttpHeaders({
1248
- Accept: "application/json",
1249
- Metadata: "true",
1250
- }),
1251
- });
1252
- }
1253
- /**
1254
- * Does a request to the authentication provider that results in a file path.
1255
- */
1256
- async function filePathRequest(identityClient, requestPrepareOptions) {
1257
- const response = await identityClient.sendRequest(coreRestPipeline.createPipelineRequest(requestPrepareOptions));
1258
- if (response.status !== 401) {
1259
- let message = "";
1260
- if (response.bodyAsText) {
1261
- message = ` Response: ${response.bodyAsText}`;
1262
- }
1263
- throw new AuthenticationError(response.status, `${msiName$3}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
1264
- }
1265
- const authHeader = response.headers.get("www-authenticate") || "";
1266
- try {
1267
- return authHeader.split("=").slice(1)[0];
1268
- }
1269
- catch (e) {
1270
- throw Error(`Invalid www-authenticate header format: ${authHeader}`);
1271
- }
1272
- }
1273
- function platformToFilePath() {
1274
- switch (process.platform) {
1275
- case "win32":
1276
- if (!process.env.PROGRAMDATA) {
1277
- throw new Error(`${msiName$3}: PROGRAMDATA environment variable has no value.`);
1278
- }
1279
- return `${process.env.PROGRAMDATA}\\AzureConnectedMachineAgent\\Tokens`;
1280
- case "linux":
1281
- return "/var/opt/azcmagent/tokens";
1282
- default:
1283
- throw new Error(`${msiName$3}: Unsupported platform ${process.platform}.`);
1284
- }
1285
- }
1286
- /**
1287
- * Validates that a given Azure Arc MSI file path is valid for use.
1288
- *
1289
- * A valid file will:
1290
- * 1. Be in the expected path for the current platform.
1291
- * 2. Have a `.key` extension.
1292
- * 3. Be at most 4096 bytes in size.
1293
- */
1294
- function validateKeyFile(filePath) {
1295
- if (!filePath) {
1296
- throw new Error(`${msiName$3}: Failed to find the token file.`);
1297
- }
1298
- if (!filePath.endsWith(".key")) {
1299
- throw new Error(`${msiName$3}: unexpected file path from HIMDS service: ${filePath}.`);
1300
- }
1301
- const expectedPath = platformToFilePath();
1302
- if (!filePath.startsWith(expectedPath)) {
1303
- throw new Error(`${msiName$3}: unexpected file path from HIMDS service: ${filePath}.`);
1304
- }
1305
- const stats = fs$1.statSync(filePath);
1306
- if (stats.size > 4096) {
1307
- throw new Error(`${msiName$3}: The file at ${filePath} is larger than expected at ${stats.size} bytes.`);
1308
- }
1309
- }
1310
- /**
1311
- * Defines how to determine whether the Azure Arc MSI is available, and also how to retrieve a token from the Azure Arc MSI.
1312
- */
1313
- const arcMsi = {
1314
- name: "arc",
1315
- async isAvailable({ scopes }) {
1316
- const resource = mapScopesToResource(scopes);
1317
- if (!resource) {
1318
- logger$l.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
1319
- return false;
1320
- }
1321
- const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
1322
- if (!result) {
1323
- logger$l.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
1324
- }
1325
- return result;
1326
- },
1327
- async getToken(configuration, getTokenOptions = {}) {
1328
- var _a;
1329
- const { identityClient, scopes, clientId, resourceId } = configuration;
1330
- if (clientId) {
1331
- logger$l.warning(`${msiName$3}: user-assigned identities not supported. The argument clientId might be ignored by the service.`);
1332
- }
1333
- if (resourceId) {
1334
- logger$l.warning(`${msiName$3}: user defined managed Identity by resource Id is not supported. Argument resourceId will be ignored.`);
1335
- }
1336
- logger$l.info(`${msiName$3}: Authenticating.`);
1337
- const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$2(scopes, clientId, resourceId)), { allowInsecureConnection: true });
1338
- const filePath = await filePathRequest(identityClient, requestOptions);
1339
- validateKeyFile(filePath);
1340
- const key = await fs$1.promises.readFile(filePath, { encoding: "utf-8" });
1341
- (_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
1342
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({}, requestOptions), {
1343
- // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
1344
- allowInsecureConnection: true }));
1345
- const tokenResponse = await identityClient.sendTokenRequest(request);
1346
- return (tokenResponse && tokenResponse.accessToken) || null;
1347
- },
1348
- };
1349
-
1350
- // Copyright (c) Microsoft Corporation.
1351
- // Licensed under the MIT license.
1352
- // This MSI can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:
1353
- //
1354
- // FROM node:12
1355
- // RUN wget https://host.any/path/bash.sh
1356
- // CMD ["bash", "bash.sh"]
1357
- //
1358
- // Where the bash script contains:
1359
- //
1360
- // curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
1361
- //
1362
- const msiName$2 = "ManagedIdentityCredential - Fabric MSI";
1363
- const logger$k = credentialLogger(msiName$2);
1364
- /**
1365
- * Generates the options used on the request for an access token.
1366
- */
1367
- function prepareRequestOptions$1(scopes, clientId, resourceId) {
1368
- const resource = mapScopesToResource(scopes);
1369
- if (!resource) {
1370
- throw new Error(`${msiName$2}: Multiple scopes are not supported.`);
1371
- }
1372
- const queryParameters = {
1373
- resource,
1374
- "api-version": azureFabricVersion,
1375
- };
1376
- if (clientId) {
1377
- queryParameters.client_id = clientId;
1378
- }
1379
- if (resourceId) {
1380
- queryParameters.msi_res_id = resourceId;
1381
- }
1382
- const query = new URLSearchParams(queryParameters);
1383
- // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
1384
- if (!process.env.IDENTITY_ENDPOINT) {
1385
- throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
1386
- }
1387
- if (!process.env.IDENTITY_HEADER) {
1388
- throw new Error("Missing environment variable: IDENTITY_HEADER");
1389
- }
1390
- return {
1391
- url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
1392
- method: "GET",
1393
- headers: coreRestPipeline.createHttpHeaders({
1394
- Accept: "application/json",
1395
- secret: process.env.IDENTITY_HEADER,
1396
- }),
1397
- };
1398
- }
1399
- /**
1400
- * Defines how to determine whether the Azure Service Fabric MSI is available, and also how to retrieve a token from the Azure Service Fabric MSI.
1401
- */
1402
- const fabricMsi = {
1403
- name: "fabricMsi",
1404
- async isAvailable({ scopes }) {
1405
- const resource = mapScopesToResource(scopes);
1406
- if (!resource) {
1407
- logger$k.info(`${msiName$2}: Unavailable. Multiple scopes are not supported.`);
1408
- return false;
1409
- }
1410
- const env = process.env;
1411
- const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT);
1412
- if (!result) {
1413
- logger$k.info(`${msiName$2}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`);
1414
- }
1415
- return result;
1416
- },
1417
- async getToken(configuration, getTokenOptions = {}) {
1418
- const { scopes, identityClient, clientId, resourceId } = configuration;
1419
- if (resourceId) {
1420
- logger$k.warning(`${msiName$2}: user defined managed Identity by resource Id is not supported. Argument resourceId might be ignored by the service.`);
1421
- }
1422
- logger$k.info([
1423
- `${msiName$2}:`,
1424
- "Using the endpoint and the secret coming from the environment variables:",
1425
- `IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,
1426
- "IDENTITY_HEADER=[REDACTED] and",
1427
- "IDENTITY_SERVER_THUMBPRINT=[REDACTED].",
1428
- ].join(" "));
1429
- const request = coreRestPipeline.createPipelineRequest(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$1(scopes, clientId, resourceId)));
1430
- request.agent = new https.Agent({
1431
- // This is necessary because Service Fabric provides a self-signed certificate.
1432
- // The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable.
1433
- rejectUnauthorized: false,
1434
- });
1435
- const tokenResponse = await identityClient.sendTokenRequest(request);
1436
- return (tokenResponse && tokenResponse.accessToken) || null;
1437
- },
1438
- };
1439
-
1440
1016
  // Copyright (c) Microsoft Corporation.
1441
1017
  // Licensed under the MIT license.
1442
1018
  /**
@@ -1776,6 +1352,41 @@ const imdsMsi = {
1776
1352
  },
1777
1353
  };
1778
1354
 
1355
+ // Copyright (c) Microsoft Corporation.
1356
+ // Licensed under the MIT license.
1357
+ // Matches the default retry configuration in expontentialRetryStrategy.ts
1358
+ const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;
1359
+ /**
1360
+ * An additional policy that retries on 404 errors. The default retry policy does not retry on
1361
+ * 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy
1362
+ * will retry on 404s with an exponential backoff.
1363
+ *
1364
+ * @param msiRetryConfig - The retry configuration for the MSI credential.
1365
+ * @returns - The policy that will retry on 404s.
1366
+ */
1367
+ function imdsRetryPolicy(msiRetryConfig) {
1368
+ return coreRestPipeline.retryPolicy([
1369
+ {
1370
+ name: "imdsRetryPolicy",
1371
+ retry: ({ retryCount, response }) => {
1372
+ if ((response === null || response === void 0 ? void 0 : response.status) !== 404) {
1373
+ return { skipStrategy: true };
1374
+ }
1375
+ // Exponentially increase the delay each time
1376
+ const exponentialDelay = msiRetryConfig.startDelayInMs * Math.pow(2, retryCount);
1377
+ // Don't let the delay exceed the maximum
1378
+ const clampedExponentialDelay = Math.min(DEFAULT_CLIENT_MAX_RETRY_INTERVAL, exponentialDelay);
1379
+ // Allow the final value to have some "jitter" (within 50% of the delay size) so
1380
+ // that retries across multiple clients don't occur simultaneously.
1381
+ const retryAfterInMs = clampedExponentialDelay / 2 + coreUtil.getRandomIntegerInclusive(0, clampedExponentialDelay / 2);
1382
+ return { retryAfterInMs };
1383
+ },
1384
+ },
1385
+ ], {
1386
+ maxRetries: msiRetryConfig.maxRetries,
1387
+ });
1388
+ }
1389
+
1779
1390
  // Copyright (c) Microsoft Corporation.
1780
1391
  // Licensed under the MIT license.
1781
1392
  /**
@@ -1918,6 +1529,10 @@ function calculateRegionalAuthority(regionalAuthority) {
1918
1529
 
1919
1530
  // Copyright (c) Microsoft Corporation.
1920
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");
1921
1536
  /**
1922
1537
  * A call to open(), but mockable
1923
1538
  * @internal
@@ -1925,13 +1540,6 @@ function calculateRegionalAuthority(regionalAuthority) {
1925
1540
  const interactiveBrowserMockable = {
1926
1541
  open,
1927
1542
  };
1928
-
1929
- // Copyright (c) Microsoft Corporation.
1930
- // Licensed under the MIT license.
1931
- /**
1932
- * The default logger used if no logger was passed in by the credential.
1933
- */
1934
- const msalLogger = credentialLogger("MsalClient");
1935
1543
  /**
1936
1544
  * Generates the configuration for MSAL (Microsoft Authentication Library).
1937
1545
  *
@@ -1956,7 +1564,7 @@ function generateMsalConfiguration(clientId, tenantId, msalClientOptions = {}) {
1956
1564
  networkClient: httpClient,
1957
1565
  loggerOptions: {
1958
1566
  loggerCallback: defaultLoggerCallback((_c = msalClientOptions.logger) !== null && _c !== void 0 ? _c : msalLogger),
1959
- logLevel: getMSALLogLevel(logger$r.getLogLevel()),
1567
+ logLevel: getMSALLogLevel(logger$m.getLogLevel()),
1960
1568
  piiLoggingEnabled: (_d = msalClientOptions.loggingOptions) === null || _d === void 0 ? void 0 : _d.enableUnsafeSupportLogging,
1961
1569
  },
1962
1570
  },
@@ -2377,8 +1985,14 @@ class ClientAssertionCredential {
2377
1985
  * @param options - Options for configuring the client which makes the authentication request.
2378
1986
  */
2379
1987
  constructor(tenantId, clientId, getAssertion, options = {}) {
2380
- if (!tenantId || !clientId || !getAssertion) {
2381
- 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.");
2382
1996
  }
2383
1997
  this.tenantId = tenantId;
2384
1998
  this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
@@ -2453,10 +2067,20 @@ class WorkloadIdentityCredential {
2453
2067
  if (tenantId) {
2454
2068
  checkTenantId(logger$g, tenantId);
2455
2069
  }
2456
- if (clientId && tenantId && this.federatedTokenFilePath) {
2457
- logger$g.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
2458
- 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`);
2459
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`);
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);
2460
2084
  }
2461
2085
  /**
2462
2086
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -2472,7 +2096,7 @@ class WorkloadIdentityCredential {
2472
2096
  In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
2473
2097
  "AZURE_TENANT_ID",
2474
2098
  "AZURE_CLIENT_ID",
2475
- "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`;
2476
2100
  logger$g.info(errorMessage);
2477
2101
  throw new CredentialUnavailableError(errorMessage);
2478
2102
  }
@@ -2509,132 +2133,76 @@ const logger$f = credentialLogger(msiName);
2509
2133
  /**
2510
2134
  * Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.
2511
2135
  */
2512
- function tokenExchangeMsi() {
2513
- return {
2514
- name: "tokenExchangeMsi",
2515
- async isAvailable({ clientId }) {
2516
- const env = process.env;
2517
- const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
2518
- env.AZURE_TENANT_ID &&
2519
- process.env.AZURE_FEDERATED_TOKEN_FILE);
2520
- if (!result) {
2521
- logger$f.info(`${msiName}: Unavailable. The environment variables needed are: AZURE_CLIENT_ID (or the client ID sent through the parameters), AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE`);
2522
- }
2523
- return result;
2524
- },
2525
- async getToken(configuration, getTokenOptions = {}) {
2526
- const { scopes, clientId } = configuration;
2527
- const identityClientTokenCredentialOptions = {};
2528
- const workloadIdentityCredential = new WorkloadIdentityCredential(Object.assign(Object.assign({ clientId, tenantId: process.env.AZURE_TENANT_ID, tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE }, identityClientTokenCredentialOptions), { disableInstanceDiscovery: true }));
2529
- const token = await workloadIdentityCredential.getToken(scopes, getTokenOptions);
2530
- return token;
2531
- },
2532
- };
2533
- }
2136
+ const tokenExchangeMsi = {
2137
+ name: "tokenExchangeMsi",
2138
+ async isAvailable({ clientId }) {
2139
+ const env = process.env;
2140
+ const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
2141
+ env.AZURE_TENANT_ID &&
2142
+ process.env.AZURE_FEDERATED_TOKEN_FILE);
2143
+ if (!result) {
2144
+ logger$f.info(`${msiName}: Unavailable. The environment variables needed are: AZURE_CLIENT_ID (or the client ID sent through the parameters), AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE`);
2145
+ }
2146
+ return result;
2147
+ },
2148
+ async getToken(configuration, getTokenOptions = {}) {
2149
+ const { scopes, clientId } = configuration;
2150
+ const identityClientTokenCredentialOptions = {};
2151
+ const workloadIdentityCredential = new WorkloadIdentityCredential(Object.assign(Object.assign({ clientId, tenantId: process.env.AZURE_TENANT_ID, tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE }, identityClientTokenCredentialOptions), { disableInstanceDiscovery: true }));
2152
+ return workloadIdentityCredential.getToken(scopes, getTokenOptions);
2153
+ },
2154
+ };
2534
2155
 
2535
2156
  // Copyright (c) Microsoft Corporation.
2536
2157
  // Licensed under the MIT license.
2537
- const logger$e = credentialLogger("ManagedIdentityCredential");
2538
- class LegacyMsiProvider {
2539
- constructor(clientIdOrOptions, options) {
2158
+ const logger$e = credentialLogger("ManagedIdentityCredential(MSAL)");
2159
+ class MsalMsiProvider {
2160
+ constructor(clientIdOrOptions, options = {}) {
2540
2161
  var _a, _b;
2541
- this.isEndpointUnavailable = null;
2542
- this.isAppTokenProviderInitialized = false;
2543
2162
  this.msiRetryConfig = {
2544
2163
  maxRetries: 5,
2545
2164
  startDelayInMs: 800,
2546
2165
  intervalIncrement: 2,
2547
2166
  };
2548
- let _options;
2167
+ let _options = {};
2549
2168
  if (typeof clientIdOrOptions === "string") {
2550
2169
  this.clientId = clientIdOrOptions;
2551
2170
  _options = options;
2552
2171
  }
2553
2172
  else {
2554
2173
  this.clientId = clientIdOrOptions === null || clientIdOrOptions === void 0 ? void 0 : clientIdOrOptions.clientId;
2555
- _options = clientIdOrOptions;
2174
+ _options = clientIdOrOptions !== null && clientIdOrOptions !== void 0 ? clientIdOrOptions : {};
2556
2175
  }
2557
2176
  this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
2558
2177
  // For JavaScript users.
2559
2178
  if (this.clientId && this.resourceId) {
2560
2179
  throw new Error(`ManagedIdentityCredential - Client Id and Resource Id can't be provided at the same time.`);
2561
2180
  }
2181
+ // ManagedIdentity uses http for local requests
2182
+ _options.allowInsecureConnection = true;
2562
2183
  if (((_a = _options === null || _options === void 0 ? void 0 : _options.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== undefined) {
2563
2184
  this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries;
2564
2185
  }
2565
- this.identityClient = new IdentityClient(_options);
2566
- this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
2567
- maxRetries: 0,
2568
- } }));
2569
- /** authority host validation and metadata discovery to be skipped in managed identity
2570
- * since this wasn't done previously before adding token cache support
2571
- */
2572
- this.confidentialApp = new msalCommon.ConfidentialClientApplication({
2573
- auth: {
2574
- authority: "https://login.microsoftonline.com/managed_identity",
2575
- clientId: (_b = this.clientId) !== null && _b !== void 0 ? _b : DeveloperSignOnClientId,
2576
- clientSecret: "dummy-secret",
2577
- cloudDiscoveryMetadata: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}',
2578
- authorityMetadata: '{"token_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/common/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/{tenantid}/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/common/kerberos","tenant_region_scope":null,"cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}',
2579
- clientCapabilities: [],
2186
+ this.identityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { additionalPolicies: [{ policy: imdsRetryPolicy(this.msiRetryConfig), position: "perCall" }] }));
2187
+ this.managedIdentityApp = new msalCommon.ManagedIdentityApplication({
2188
+ managedIdentityIdParams: {
2189
+ userAssignedClientId: this.clientId,
2190
+ userAssignedResourceId: this.resourceId,
2580
2191
  },
2581
2192
  system: {
2193
+ // todo: proxyUrl?
2194
+ disableInternalRetries: true,
2195
+ networkClient: this.identityClient,
2582
2196
  loggerOptions: {
2583
- logLevel: getMSALLogLevel(logger$r.getLogLevel()),
2197
+ logLevel: getMSALLogLevel(logger$m.getLogLevel()),
2198
+ piiLoggingEnabled: (_b = options.loggingOptions) === null || _b === void 0 ? void 0 : _b.enableUnsafeSupportLogging,
2199
+ loggerCallback: defaultLoggerCallback(logger$e),
2584
2200
  },
2585
2201
  },
2586
2202
  });
2587
- }
2588
- async cachedAvailableMSI(scopes, getTokenOptions) {
2589
- if (this.cachedMSI) {
2590
- return this.cachedMSI;
2591
- }
2592
- const MSIs = [
2593
- arcMsi,
2594
- fabricMsi,
2595
- appServiceMsi2019,
2596
- appServiceMsi2017,
2597
- cloudShellMsi,
2598
- tokenExchangeMsi(),
2599
- imdsMsi,
2600
- ];
2601
- for (const msi of MSIs) {
2602
- if (await msi.isAvailable({
2603
- scopes,
2604
- identityClient: this.isAvailableIdentityClient,
2605
- clientId: this.clientId,
2606
- resourceId: this.resourceId,
2607
- getTokenOptions,
2608
- })) {
2609
- this.cachedMSI = msi;
2610
- return msi;
2611
- }
2612
- }
2613
- throw new CredentialUnavailableError(`ManagedIdentityCredential - No MSI credential available`);
2614
- }
2615
- async authenticateManagedIdentity(scopes, getTokenOptions) {
2616
- const { span, updatedOptions } = tracingClient.startSpan(`ManagedIdentityCredential.authenticateManagedIdentity`, getTokenOptions);
2617
- try {
2618
- // Determining the available MSI, and avoiding checking for other MSIs while the program is running.
2619
- const availableMSI = await this.cachedAvailableMSI(scopes, updatedOptions);
2620
- return availableMSI.getToken({
2621
- identityClient: this.identityClient,
2622
- scopes,
2623
- clientId: this.clientId,
2624
- resourceId: this.resourceId,
2625
- retryConfig: this.msiRetryConfig,
2626
- }, updatedOptions);
2627
- }
2628
- catch (err) {
2629
- span.setStatus({
2630
- status: "error",
2631
- error: err,
2632
- });
2633
- throw err;
2634
- }
2635
- finally {
2636
- span.end();
2637
- }
2203
+ this.isAvailableIdentityClient = new IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
2204
+ maxRetries: 0,
2205
+ } }));
2638
2206
  }
2639
2207
  /**
2640
2208
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -2645,133 +2213,93 @@ class LegacyMsiProvider {
2645
2213
  * @param options - The options used to configure any requests this
2646
2214
  * TokenCredential implementation might make.
2647
2215
  */
2648
- async getToken(scopes, options) {
2649
- let result = null;
2650
- const { span, updatedOptions } = tracingClient.startSpan(`ManagedIdentityCredential.getToken`, options);
2651
- try {
2652
- // isEndpointAvailable can be true, false, or null,
2653
- // If it's null, it means we don't yet know whether
2654
- // the endpoint is available and need to check for it.
2655
- if (this.isEndpointUnavailable !== true) {
2656
- const availableMSI = await this.cachedAvailableMSI(scopes, updatedOptions);
2657
- if (availableMSI.name === "tokenExchangeMsi") {
2658
- result = await this.authenticateManagedIdentity(scopes, updatedOptions);
2659
- }
2660
- else {
2661
- const appTokenParameters = {
2662
- correlationId: this.identityClient.getCorrelationId(),
2663
- tenantId: (options === null || options === void 0 ? void 0 : options.tenantId) || "managed_identity",
2664
- scopes: Array.isArray(scopes) ? scopes : [scopes],
2665
- claims: options === null || options === void 0 ? void 0 : options.claims,
2666
- };
2667
- // Added a check to see if SetAppTokenProvider was already defined.
2668
- this.initializeSetAppTokenProvider();
2669
- const authenticationResult = await this.confidentialApp.acquireTokenByClientCredential(Object.assign({}, appTokenParameters));
2670
- result = this.handleResult(scopes, authenticationResult || undefined);
2216
+ async getToken(scopes, options = {}) {
2217
+ logger$e.getToken.info("Using the MSAL provider for Managed Identity.");
2218
+ const resource = mapScopesToResource(scopes);
2219
+ if (!resource) {
2220
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Multiple scopes are not supported. Scopes: ${JSON.stringify(scopes)}`);
2221
+ }
2222
+ return tracingClient.withSpan("ManagedIdentityCredential.getToken", options, async () => {
2223
+ try {
2224
+ const isTokenExchangeMsi = await tokenExchangeMsi.isAvailable({
2225
+ scopes,
2226
+ clientId: this.clientId,
2227
+ getTokenOptions: options,
2228
+ identityClient: this.identityClient,
2229
+ resourceId: this.resourceId,
2230
+ });
2231
+ // Most scenarios are handled by MSAL except for two:
2232
+ // AKS pod identity - MSAL does not implement the token exchange flow.
2233
+ // IMDS Endpoint probing - MSAL does not do any probing before trying to get a token.
2234
+ // As a DefaultAzureCredential optimization we probe the IMDS endpoint with a short timeout and no retries before actually trying to get a token
2235
+ // We will continue to implement these features in the Identity library.
2236
+ const identitySource = this.managedIdentityApp.getManagedIdentitySource();
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}`);
2239
+ if (isTokenExchangeMsi) {
2240
+ // In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
2241
+ logger$e.getToken.info("Using the token exchange managed identity.");
2242
+ const result = await tokenExchangeMsi.getToken({
2243
+ scopes,
2244
+ clientId: this.clientId,
2245
+ identityClient: this.identityClient,
2246
+ retryConfig: this.msiRetryConfig,
2247
+ resourceId: this.resourceId,
2248
+ });
2249
+ if (result === null) {
2250
+ throw new CredentialUnavailableError("Attempted to use the token exchange managed identity, but received a null response.");
2251
+ }
2252
+ return result;
2671
2253
  }
2672
- if (result === null) {
2673
- // If authenticateManagedIdentity returns null,
2674
- // it means no MSI endpoints are available.
2675
- // If so, we avoid trying to reach to them in future requests.
2676
- this.isEndpointUnavailable = true;
2677
- // It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
2678
- // yet we had no access token. For this reason, we'll throw once with a specific message:
2679
- const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2680
- logger$e.getToken.info(formatError(scopes, error));
2681
- throw error;
2254
+ else if (isImdsMsi) {
2255
+ // In the IMDS scenario we will probe the IMDS endpoint to ensure it's available before trying to get a token.
2256
+ // If the IMDS endpoint is not available and this is the source that MSAL will use, we will fail-fast with an error that tells DAC to move to the next credential.
2257
+ logger$e.getToken.info("Using the IMDS endpoint to probe for availability.");
2258
+ const isAvailable = await imdsMsi.isAvailable({
2259
+ scopes,
2260
+ clientId: this.clientId,
2261
+ getTokenOptions: options,
2262
+ identityClient: this.isAvailableIdentityClient,
2263
+ resourceId: this.resourceId,
2264
+ });
2265
+ if (!isAvailable) {
2266
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Attempted to use the IMDS endpoint, but it is not available.`);
2267
+ }
2682
2268
  }
2683
- // Since `authenticateManagedIdentity` didn't throw, and the result was not null,
2684
- // We will assume that this endpoint is reachable from this point forward,
2685
- // and avoid pinging again to it.
2686
- this.isEndpointUnavailable = false;
2687
- }
2688
- else {
2689
- // We've previously determined that the endpoint was unavailable,
2690
- // either because it was unreachable or permanently unable to authenticate.
2691
- const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
2692
- logger$e.getToken.info(formatError(scopes, error));
2693
- throw error;
2694
- }
2695
- logger$e.getToken.info(formatSuccess(scopes));
2696
- return result;
2697
- }
2698
- catch (err) {
2699
- // CredentialUnavailable errors are expected to reach here.
2700
- // We intend them to bubble up, so that DefaultAzureCredential can catch them.
2701
- if (err.name === "AuthenticationRequiredError") {
2702
- throw err;
2703
- }
2704
- // Expected errors to reach this point:
2705
- // - Errors coming from a method unexpectedly breaking.
2706
- // - When identityClient.sendTokenRequest throws, in which case
2707
- // if the status code was 400, it means that the endpoint is working,
2708
- // but no identity is available.
2709
- span.setStatus({
2710
- status: "error",
2711
- error: err,
2712
- });
2713
- // If either the network is unreachable,
2714
- // we can safely assume the credential is unavailable.
2715
- if (err.code === "ENETUNREACH") {
2716
- const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. Network unreachable. Message: ${err.message}`);
2717
- logger$e.getToken.info(formatError(scopes, error));
2718
- throw error;
2719
- }
2720
- // If either the host was unreachable,
2721
- // we can safely assume the credential is unavailable.
2722
- if (err.code === "EHOSTUNREACH") {
2723
- const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. No managed identity endpoint found. Message: ${err.message}`);
2724
- logger$e.getToken.info(formatError(scopes, error));
2725
- throw error;
2726
- }
2727
- // If err.statusCode has a value of 400, it comes from sendTokenRequest,
2728
- // and it means that the endpoint is working, but that no identity is available.
2729
- if (err.statusCode === 400) {
2730
- throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
2269
+ // If we got this far, it means:
2270
+ // - This is not a tokenExchangeMsi,
2271
+ // - We already probed for IMDS endpoint availability and failed-fast if it's unreachable.
2272
+ // We can proceed normally by calling MSAL for a token.
2273
+ logger$e.getToken.info("Calling into MSAL for managed identity token.");
2274
+ const token = await this.managedIdentityApp.acquireToken({
2275
+ resource,
2276
+ });
2277
+ this.ensureValidMsalToken(scopes, token, options);
2278
+ logger$e.getToken.info(formatSuccess(scopes));
2279
+ return {
2280
+ expiresOnTimestamp: token.expiresOn.getTime(),
2281
+ token: token.accessToken,
2282
+ };
2731
2283
  }
2732
- // This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
2733
- // rather than just timing out, as expected.
2734
- if (err.statusCode === 403 || err.code === 403) {
2735
- if (err.message.includes("unreachable")) {
2736
- const error = new CredentialUnavailableError(`ManagedIdentityCredential: Unavailable. Network unreachable. Message: ${err.message}`);
2737
- logger$e.getToken.info(formatError(scopes, error));
2738
- throw error;
2284
+ catch (err) {
2285
+ logger$e.getToken.error(formatError(scopes, err));
2286
+ // AuthenticationRequiredError described as Error to enforce authentication after trying to retrieve a token silently.
2287
+ // TODO: why would this _ever_ happen considering we're not trying the silent request in this flow?
2288
+ if (err.name === "AuthenticationRequiredError") {
2289
+ throw err;
2739
2290
  }
2291
+ if (isNetworkError(err)) {
2292
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err });
2293
+ }
2294
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err });
2740
2295
  }
2741
- // If the error has no status code, we can assume there was no available identity.
2742
- // This will throw silently during any ChainedTokenCredential.
2743
- if (err.statusCode === undefined) {
2744
- throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`);
2745
- }
2746
- // Any other error should break the chain.
2747
- throw new AuthenticationError(err.statusCode, {
2748
- error: `ManagedIdentityCredential authentication failed.`,
2749
- error_description: err.message,
2750
- });
2751
- }
2752
- finally {
2753
- // Finally is always called, both if we return and if we throw in the above try/catch.
2754
- span.end();
2755
- }
2756
- }
2757
- /**
2758
- * Handles the MSAL authentication result.
2759
- * If the result has an account, we update the local account reference.
2760
- * If the token received is invalid, an error will be thrown depending on what's missing.
2761
- */
2762
- handleResult(scopes, result, getTokenOptions) {
2763
- this.ensureValidMsalToken(scopes, result, getTokenOptions);
2764
- logger$e.getToken.info(formatSuccess(scopes));
2765
- return {
2766
- token: result.accessToken,
2767
- expiresOnTimestamp: result.expiresOn.getTime(),
2768
- };
2296
+ });
2769
2297
  }
2770
2298
  /**
2771
2299
  * Ensures the validity of the MSAL token
2772
2300
  */
2773
2301
  ensureValidMsalToken(scopes, msalToken, getTokenOptions) {
2774
- const error = (message) => {
2302
+ const createError = (message) => {
2775
2303
  logger$e.getToken.info(message);
2776
2304
  return new AuthenticationRequiredError({
2777
2305
  scopes: Array.isArray(scopes) ? scopes : [scopes],
@@ -2780,43 +2308,33 @@ class LegacyMsiProvider {
2780
2308
  });
2781
2309
  };
2782
2310
  if (!msalToken) {
2783
- throw error("No response");
2311
+ throw createError("No response.");
2784
2312
  }
2785
2313
  if (!msalToken.expiresOn) {
2786
- throw error(`Response had no "expiresOn" property.`);
2314
+ throw createError(`Response had no "expiresOn" property.`);
2787
2315
  }
2788
2316
  if (!msalToken.accessToken) {
2789
- throw error(`Response had no "accessToken" property.`);
2790
- }
2791
- }
2792
- initializeSetAppTokenProvider() {
2793
- if (!this.isAppTokenProviderInitialized) {
2794
- this.confidentialApp.SetAppTokenProvider(async (appTokenProviderParameters) => {
2795
- logger$e.info(`SetAppTokenProvider invoked with parameters- ${JSON.stringify(appTokenProviderParameters)}`);
2796
- const getTokenOptions = Object.assign({}, appTokenProviderParameters);
2797
- logger$e.info(`authenticateManagedIdentity invoked with scopes- ${JSON.stringify(appTokenProviderParameters.scopes)} and getTokenOptions - ${JSON.stringify(getTokenOptions)}`);
2798
- const resultToken = await this.authenticateManagedIdentity(appTokenProviderParameters.scopes, getTokenOptions);
2799
- if (resultToken) {
2800
- logger$e.info(`SetAppTokenProvider will save the token in cache`);
2801
- const expiresInSeconds = (resultToken === null || resultToken === void 0 ? void 0 : resultToken.expiresOnTimestamp)
2802
- ? Math.floor((resultToken.expiresOnTimestamp - Date.now()) / 1000)
2803
- : 0;
2804
- return {
2805
- accessToken: resultToken === null || resultToken === void 0 ? void 0 : resultToken.token,
2806
- expiresInSeconds,
2807
- };
2808
- }
2809
- else {
2810
- logger$e.info(`SetAppTokenProvider token has "no_access_token_returned" as the saved token`);
2811
- return {
2812
- accessToken: "no_access_token_returned",
2813
- expiresInSeconds: 0,
2814
- };
2815
- }
2816
- });
2817
- this.isAppTokenProviderInitialized = true;
2317
+ throw createError(`Response had no "accessToken" property.`);
2318
+ }
2319
+ }
2320
+ }
2321
+ function isNetworkError(err) {
2322
+ // MSAL error
2323
+ if (err.errorCode === "network_error") {
2324
+ return true;
2325
+ }
2326
+ // Probe errors
2327
+ if (err.code === "ENETUNREACH" || err.code === "EHOSTUNREACH") {
2328
+ return true;
2329
+ }
2330
+ // This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
2331
+ // rather than just timing out, as expected.
2332
+ if (err.statusCode === 403 || err.code === 403) {
2333
+ if (err.message.includes("unreachable")) {
2334
+ return true;
2818
2335
  }
2819
2336
  }
2337
+ return false;
2820
2338
  }
2821
2339
 
2822
2340
  // Copyright (c) Microsoft Corporation.
@@ -2835,7 +2353,11 @@ class ManagedIdentityCredential {
2835
2353
  * @hidden
2836
2354
  */
2837
2355
  constructor(clientIdOrOptions, options) {
2838
- this.implProvider = new LegacyMsiProvider(clientIdOrOptions, options);
2356
+ // https://github.com/Azure/azure-sdk-for-js/issues/30189
2357
+ // If needed, you may release a hotfix to quickly rollback to the legacy implementation by changing the following line to:
2358
+ // this.implProvider = new LegacyMsiProvider(clientIdOrOptions, options);
2359
+ // Once stabilized, you can remove the legacy implementation and inline the msalMsiProvider code here as a drop-in replacement.
2360
+ this.implProvider = new MsalMsiProvider(clientIdOrOptions, options);
2839
2361
  }
2840
2362
  /**
2841
2363
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
@@ -3345,33 +2867,45 @@ class AzurePowerShellCredential {
3345
2867
  commandStack.shift();
3346
2868
  continue;
3347
2869
  }
3348
- let tenantSection = "";
3349
- if (tenantId) {
3350
- tenantSection = `-TenantId "${tenantId}"`;
3351
- }
3352
2870
  const results = await runCommands([
3353
2871
  [
3354
2872
  powerShellCommand,
3355
2873
  "-NoProfile",
3356
2874
  "-NonInteractive",
3357
2875
  "-Command",
3358
- "Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru",
3359
- ],
3360
- [
3361
- powerShellCommand,
3362
- "-NoProfile",
3363
- "-NonInteractive",
3364
- "-Command",
3365
- `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
+ `,
3366
2905
  ],
3367
2906
  ]);
3368
- const result = results[1];
3369
- try {
3370
- return JSON.parse(result);
3371
- }
3372
- catch (e) {
3373
- throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
3374
- }
2907
+ const result = results[0];
2908
+ return parseJsonToken(result);
3375
2909
  }
3376
2910
  throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
3377
2911
  }
@@ -3418,6 +2952,38 @@ class AzurePowerShellCredential {
3418
2952
  });
3419
2953
  }
3420
2954
  }
2955
+ /**
2956
+ *
2957
+ * @internal
2958
+ */
2959
+ async function parseJsonToken(result) {
2960
+ const jsonRegex = /{[^{}]*}/g;
2961
+ const matches = result.match(jsonRegex);
2962
+ let resultWithoutToken = result;
2963
+ if (matches) {
2964
+ try {
2965
+ for (const item of matches) {
2966
+ try {
2967
+ const jsonContent = JSON.parse(item);
2968
+ if (jsonContent === null || jsonContent === void 0 ? void 0 : jsonContent.Token) {
2969
+ resultWithoutToken = resultWithoutToken.replace(item, "");
2970
+ if (resultWithoutToken) {
2971
+ logger$b.getToken.warning(resultWithoutToken);
2972
+ }
2973
+ return jsonContent;
2974
+ }
2975
+ }
2976
+ catch (e) {
2977
+ continue;
2978
+ }
2979
+ }
2980
+ }
2981
+ catch (e) {
2982
+ throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
2983
+ }
2984
+ }
2985
+ throw new Error(`No access token found in the output. Received output: ${result}`);
2986
+ }
3421
2987
 
3422
2988
  // Copyright (c) Microsoft Corporation.
3423
2989
  // Licensed under the MIT license.
@@ -3550,7 +3116,8 @@ class ClientCertificateCredential {
3550
3116
  });
3551
3117
  }
3552
3118
  async buildClientCertificate() {
3553
- const parts = await this.parseCertificate();
3119
+ var _a;
3120
+ const parts = await parseCertificate(this.certificateConfiguration, (_a = this.sendCertificateChain) !== null && _a !== void 0 ? _a : false);
3554
3121
  let privateKey;
3555
3122
  if (this.certificateConfiguration.certificatePassword !== undefined) {
3556
3123
  privateKey = crypto.createPrivateKey({
@@ -3573,34 +3140,41 @@ class ClientCertificateCredential {
3573
3140
  x5c: parts.x5c,
3574
3141
  };
3575
3142
  }
3576
- async parseCertificate() {
3577
- const certificate = this.certificateConfiguration.certificate;
3578
- const certificatePath = this.certificateConfiguration.certificatePath;
3579
- const certificateContents = certificate || (await promises.readFile(certificatePath, "utf8"));
3580
- const x5c = this.sendCertificateChain ? certificateContents : undefined;
3581
- const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
3582
- const publicKeys = [];
3583
- // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
3584
- let match;
3585
- do {
3586
- match = certificatePattern.exec(certificateContents);
3587
- if (match) {
3588
- publicKeys.push(match[3]);
3589
- }
3590
- } while (match);
3591
- if (publicKeys.length === 0) {
3592
- throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
3593
- }
3594
- const thumbprint = crypto.createHash("sha1")
3595
- .update(Buffer.from(publicKeys[0], "base64"))
3596
- .digest("hex")
3597
- .toUpperCase();
3598
- return {
3599
- certificateContents,
3600
- thumbprint,
3601
- x5c,
3602
- };
3603
- }
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]);
3164
+ }
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
+ };
3604
3178
  }
3605
3179
 
3606
3180
  // Copyright (c) Microsoft Corporation.
@@ -3626,8 +3200,14 @@ class ClientSecretCredential {
3626
3200
  * @param options - Options for configuring the client which makes the authentication request.
3627
3201
  */
3628
3202
  constructor(tenantId, clientId, clientSecret, options = {}) {
3629
- if (!tenantId || !clientId || !clientSecret) {
3630
- 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.");
3631
3211
  }
3632
3212
  this.clientSecret = clientSecret;
3633
3213
  this.tenantId = tenantId;
@@ -3673,8 +3253,17 @@ class UsernamePasswordCredential {
3673
3253
  * @param options - Options for configuring the client which makes the authentication request.
3674
3254
  */
3675
3255
  constructor(tenantId, clientId, username, password, options = {}) {
3676
- if (!tenantId || !clientId || !username || !password) {
3677
- 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.");
3678
3267
  }
3679
3268
  this.tenantId = tenantId;
3680
3269
  this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
@@ -3721,6 +3310,7 @@ const AllSupportedEnvironmentVariables = [
3721
3310
  "AZURE_USERNAME",
3722
3311
  "AZURE_PASSWORD",
3723
3312
  "AZURE_ADDITIONALLY_ALLOWED_TENANTS",
3313
+ "AZURE_CLIENT_SEND_CERTIFICATE_CHAIN",
3724
3314
  ];
3725
3315
  function getAdditionallyAllowedTenants() {
3726
3316
  var _a;
@@ -3729,6 +3319,13 @@ function getAdditionallyAllowedTenants() {
3729
3319
  }
3730
3320
  const credentialName$2 = "EnvironmentCredential";
3731
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
+ }
3732
3329
  /**
3733
3330
  * Enables authentication to Microsoft Entra ID using a client secret or certificate, or as a user
3734
3331
  * with a username and password.
@@ -3748,6 +3345,7 @@ class EnvironmentCredential {
3748
3345
  * - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
3749
3346
  * - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
3750
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.
3751
3349
  *
3752
3350
  * Alternatively, users can provide environment variables for username and password authentication:
3753
3351
  * - `AZURE_USERNAME`: Username to authenticate with.
@@ -3765,7 +3363,8 @@ class EnvironmentCredential {
3765
3363
  logger$6.info(`Found the following environment variables: ${assigned}`);
3766
3364
  const tenantId = process.env.AZURE_TENANT_ID, clientId = process.env.AZURE_CLIENT_ID, clientSecret = process.env.AZURE_CLIENT_SECRET;
3767
3365
  const additionallyAllowedTenantIds = getAdditionallyAllowedTenants();
3768
- const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds });
3366
+ const sendCertificateChain = getSendCertificateChain();
3367
+ const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds, sendCertificateChain });
3769
3368
  if (tenantId) {
3770
3369
  checkTenantId(logger$6, tenantId);
3771
3370
  }
@@ -4026,7 +3625,7 @@ class InteractiveBrowserCredential {
4026
3625
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
4027
3626
  * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
4028
3627
  *
4029
- * 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.
4030
3629
  *
4031
3630
  * On Node.js, this credential has [Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) enabled by default.
4032
3631
  * PKCE is a security feature that mitigates authentication code interception attacks.
@@ -4112,7 +3711,7 @@ class DeviceCodeCredential {
4112
3711
  * Authenticates with Microsoft Entra ID and returns an access token if successful.
4113
3712
  * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
4114
3713
  *
4115
- * 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.
4116
3715
  *
4117
3716
  * @param scopes - The list of scopes for which the token will have access.
4118
3717
  * @param options - The options used to configure any requests this
@@ -4146,8 +3745,17 @@ class AzurePipelinesCredential {
4146
3745
  * @param options - The identity client options to use for authentication.
4147
3746
  */
4148
3747
  constructor(tenantId, clientId, serviceConnectionId, systemAccessToken, options) {
4149
- if (!clientId || !tenantId || !serviceConnectionId || !systemAccessToken) {
4150
- 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.`);
4151
3759
  }
4152
3760
  this.identityClient = new IdentityClient(options);
4153
3761
  checkTenantId(logger$2, tenantId);
@@ -4200,31 +3808,46 @@ class AzurePipelinesCredential {
4200
3808
  }),
4201
3809
  });
4202
3810
  const response = await this.identityClient.sendRequest(request);
4203
- const text = response.bodyAsText;
4204
- if (!text) {
4205
- logger$2.error(`${credentialName$1}: Authenticated Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
4206
- throw new AuthenticationError(response.status, `${credentialName$1}: Authenticated Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
3811
+ return handleOidcResponse(response);
3812
+ }
3813
+ }
3814
+ function handleOidcResponse(response) {
3815
+ const text = response.bodyAsText;
3816
+ if (!text) {
3817
+ logger$2.error(`${credentialName$1}: Authentication Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
3818
+ throw new AuthenticationError(response.status, {
3819
+ error: `${credentialName$1}: Authentication Failed. Received null token from OIDC request.`,
3820
+ error_description: `${JSON.stringify(response)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
3821
+ });
3822
+ }
3823
+ try {
3824
+ const result = JSON.parse(text);
3825
+ if (result === null || result === void 0 ? void 0 : result.oidcToken) {
3826
+ return result.oidcToken;
4207
3827
  }
4208
- try {
4209
- const result = JSON.parse(text);
4210
- if (result === null || result === void 0 ? void 0 : result.oidcToken) {
4211
- return result.oidcToken;
4212
- }
4213
- else {
4214
- let errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
4215
- if (response.status !== 200) {
4216
- errorMessage += `Response = ${JSON.stringify(result)}`;
4217
- }
4218
- logger$2.error(errorMessage);
4219
- throw new AuthenticationError(response.status, errorMessage);
3828
+ else {
3829
+ const errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
3830
+ let errorDescription = ``;
3831
+ if (response.status !== 200) {
3832
+ errorDescription = `Complete response - ${JSON.stringify(result)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`;
4220
3833
  }
4221
- }
4222
- catch (e) {
4223
- logger$2.error(e.message);
4224
- logger$2.error(`${credentialName$1}: Authentication Failed. oidcToken field not detected in the response. Response = ${text}`);
4225
- throw new AuthenticationError(response.status, `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response. Response = ${text}`);
3834
+ logger$2.error(errorMessage);
3835
+ logger$2.error(errorDescription);
3836
+ throw new AuthenticationError(response.status, {
3837
+ error: errorMessage,
3838
+ error_description: errorDescription,
3839
+ });
4226
3840
  }
4227
3841
  }
3842
+ catch (e) {
3843
+ const errorDetails = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
3844
+ logger$2.error(`Response from service = ${text} and error message = ${e.message}`);
3845
+ logger$2.error(errorDetails);
3846
+ throw new AuthenticationError(response.status, {
3847
+ error: errorDetails,
3848
+ error_description: `Response = ${text}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
3849
+ });
3850
+ }
4228
3851
  }
4229
3852
 
4230
3853
  // Copyright (c) Microsoft Corporation.
@@ -4294,11 +3917,17 @@ class OnBehalfOfCredential {
4294
3917
  const { certificatePath, sendCertificateChain } = options;
4295
3918
  const { getAssertion } = options;
4296
3919
  const { tenantId, clientId, userAssertionToken, additionallyAllowedTenants: additionallyAllowedTenantIds, } = options;
4297
- if (!tenantId ||
4298
- !clientId ||
4299
- !(clientSecret || certificatePath || getAssertion) ||
4300
- !userAssertionToken) {
4301
- 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.`);
4302
3931
  }
4303
3932
  this.certificatePath = certificatePath;
4304
3933
  this.clientSecret = clientSecret;
@@ -4467,7 +4096,7 @@ exports.WorkloadIdentityCredential = WorkloadIdentityCredential;
4467
4096
  exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
4468
4097
  exports.getBearerTokenProvider = getBearerTokenProvider;
4469
4098
  exports.getDefaultAzureCredential = getDefaultAzureCredential;
4470
- exports.logger = logger$q;
4099
+ exports.logger = logger$l;
4471
4100
  exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
4472
4101
  exports.useIdentityPlugin = useIdentityPlugin;
4473
4102
  //# sourceMappingURL=index.js.map