@azure/identity 2.0.0-beta.5 → 2.0.1

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.

Potentially problematic release.


This version of @azure/identity might be problematic. Click here for more details.

Files changed (130) hide show
  1. package/CHANGELOG.md +189 -12
  2. package/README.md +77 -24
  3. package/dist/index.js +705 -386
  4. package/dist/index.js.map +1 -1
  5. package/dist-esm/src/client/identityClient.js +3 -7
  6. package/dist-esm/src/client/identityClient.js.map +1 -1
  7. package/dist-esm/src/credentials/authorizationCodeCredential.browser.js +1 -1
  8. package/dist-esm/src/credentials/authorizationCodeCredential.browser.js.map +1 -1
  9. package/dist-esm/src/credentials/authorizationCodeCredential.js +12 -76
  10. package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
  11. package/dist-esm/src/credentials/{applicationCredential.browser.js → azureApplicationCredential.browser.js} +9 -4
  12. package/dist-esm/src/credentials/azureApplicationCredential.browser.js.map +1 -0
  13. package/dist-esm/src/credentials/azureApplicationCredential.js +36 -0
  14. package/dist-esm/src/credentials/azureApplicationCredential.js.map +1 -0
  15. package/dist-esm/src/credentials/azureCliCredential.browser.js +7 -0
  16. package/dist-esm/src/credentials/azureCliCredential.browser.js.map +1 -1
  17. package/dist-esm/src/credentials/azureCliCredential.js +10 -10
  18. package/dist-esm/src/credentials/azureCliCredential.js.map +1 -1
  19. package/dist-esm/src/credentials/azurePowerShellCredential.browser.js +3 -1
  20. package/dist-esm/src/credentials/azurePowerShellCredential.browser.js.map +1 -1
  21. package/dist-esm/src/credentials/azurePowerShellCredential.js +13 -13
  22. package/dist-esm/src/credentials/azurePowerShellCredential.js.map +1 -1
  23. package/dist-esm/src/credentials/chainedTokenCredential.js +6 -5
  24. package/dist-esm/src/credentials/chainedTokenCredential.js.map +1 -1
  25. package/dist-esm/src/credentials/clientCertificateCredential.browser.js +7 -0
  26. package/dist-esm/src/credentials/clientCertificateCredential.browser.js.map +1 -1
  27. package/dist-esm/src/credentials/clientCertificateCredential.js +19 -13
  28. package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
  29. package/dist-esm/src/credentials/clientCertificateCredentialOptions.js.map +1 -1
  30. package/dist-esm/src/credentials/clientSecretCredential.browser.js +2 -5
  31. package/dist-esm/src/credentials/clientSecretCredential.browser.js.map +1 -1
  32. package/dist-esm/src/credentials/clientSecretCredential.js +3 -0
  33. package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
  34. package/dist-esm/src/credentials/clientSecretCredentialOptions.js.map +1 -1
  35. package/dist-esm/src/credentials/credentialPersistenceOptions.js.map +1 -1
  36. package/dist-esm/src/credentials/defaultAzureCredential.js +21 -20
  37. package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
  38. package/dist-esm/src/credentials/deviceCodeCredential.browser.js +7 -0
  39. package/dist-esm/src/credentials/deviceCodeCredential.browser.js.map +1 -1
  40. package/dist-esm/src/credentials/deviceCodeCredential.js +14 -0
  41. package/dist-esm/src/credentials/deviceCodeCredential.js.map +1 -1
  42. package/dist-esm/src/credentials/environmentCredential.browser.js +7 -0
  43. package/dist-esm/src/credentials/environmentCredential.browser.js.map +1 -1
  44. package/dist-esm/src/credentials/environmentCredential.js +5 -21
  45. package/dist-esm/src/credentials/environmentCredential.js.map +1 -1
  46. package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js +7 -7
  47. package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js.map +1 -1
  48. package/dist-esm/src/credentials/interactiveBrowserCredential.js +7 -7
  49. package/dist-esm/src/credentials/interactiveBrowserCredential.js.map +1 -1
  50. package/dist-esm/src/credentials/interactiveBrowserCredentialOptions.js.map +1 -1
  51. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +21 -10
  52. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
  53. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +24 -13
  54. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
  55. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +22 -11
  56. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
  57. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +24 -7
  58. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
  59. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +57 -39
  60. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
  61. package/dist-esm/src/credentials/managedIdentityCredential/index.js +16 -14
  62. package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
  63. package/dist-esm/src/credentials/managedIdentityCredential/models.js.map +1 -1
  64. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +82 -0
  65. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -0
  66. package/dist-esm/src/credentials/managedIdentityCredential/utils.js +14 -6
  67. package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
  68. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js +23 -0
  69. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js.map +1 -0
  70. package/dist-esm/src/credentials/onBehalfOfCredential.js +57 -0
  71. package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -0
  72. package/dist-esm/src/credentials/{visualStudioCodeCredentialExtension.js → onBehalfOfCredentialOptions.js} +1 -1
  73. package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -0
  74. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js +11 -14
  75. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
  76. package/dist-esm/src/credentials/usernamePasswordCredential.js +3 -2
  77. package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
  78. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js +7 -1
  79. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js.map +1 -1
  80. package/dist-esm/src/credentials/visualStudioCodeCredential.js +16 -8
  81. package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
  82. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js +4 -0
  83. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js.map +1 -0
  84. package/dist-esm/src/{client/errors.js → errors.js} +16 -1
  85. package/dist-esm/src/errors.js.map +1 -0
  86. package/dist-esm/src/index.js +3 -5
  87. package/dist-esm/src/index.js.map +1 -1
  88. package/dist-esm/src/msal/browserFlows/browserCommon.js +8 -7
  89. package/dist-esm/src/msal/browserFlows/browserCommon.js.map +1 -1
  90. package/dist-esm/src/msal/browserFlows/msalAuthCode.js +12 -4
  91. package/dist-esm/src/msal/browserFlows/msalAuthCode.js.map +1 -1
  92. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +41 -0
  93. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -0
  94. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +49 -29
  95. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
  96. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
  97. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +56 -0
  98. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -0
  99. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +1 -1
  100. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +1 -1
  101. package/dist-esm/src/msal/nodeFlows/nodeCommon.js +19 -8
  102. package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +1 -1
  103. package/dist-esm/src/msal/nodeFlows/tokenCachePersistenceOptions.js.map +1 -1
  104. package/dist-esm/src/msal/utils.js +7 -4
  105. package/dist-esm/src/msal/utils.js.map +1 -1
  106. package/dist-esm/src/plugins/consumer.browser.js +7 -0
  107. package/dist-esm/src/plugins/consumer.browser.js.map +1 -0
  108. package/dist-esm/src/{extensions → plugins}/consumer.js +12 -12
  109. package/dist-esm/src/plugins/consumer.js.map +1 -0
  110. package/dist-esm/src/{extensions → plugins}/provider.js +0 -0
  111. package/dist-esm/src/plugins/provider.js.map +1 -0
  112. package/dist-esm/src/util/tracing.js +1 -1
  113. package/dist-esm/src/util/tracing.js.map +1 -1
  114. package/dist-esm/src/util/validateMultiTenant.browser.js +22 -0
  115. package/dist-esm/src/util/validateMultiTenant.browser.js.map +1 -0
  116. package/dist-esm/src/util/validateMultiTenant.js +17 -12
  117. package/dist-esm/src/util/validateMultiTenant.js.map +1 -1
  118. package/package.json +16 -16
  119. package/types/identity.d.ts +246 -261
  120. package/dist-esm/src/client/errors.js.map +0 -1
  121. package/dist-esm/src/credentials/applicationCredential.browser.js.map +0 -1
  122. package/dist-esm/src/credentials/applicationCredential.js +0 -37
  123. package/dist-esm/src/credentials/applicationCredential.js.map +0 -1
  124. package/dist-esm/src/credentials/visualStudioCodeCredentialExtension.js.map +0 -1
  125. package/dist-esm/src/extensions/consumer.browser.js +0 -7
  126. package/dist-esm/src/extensions/consumer.browser.js.map +0 -1
  127. package/dist-esm/src/extensions/consumer.js.map +0 -1
  128. package/dist-esm/src/extensions/provider.js.map +0 -1
  129. package/dist-esm/src/msal/errors.js +0 -22
  130. package/dist-esm/src/msal/errors.js.map +0 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ var coreTracing = require('@azure/core-tracing');
10
10
  var coreUtil = require('@azure/core-util');
11
11
  var coreRestPipeline = require('@azure/core-rest-pipeline');
12
12
  var abortController = require('@azure/abort-controller');
13
- var logger$h = require('@azure/logger');
13
+ var logger$k = require('@azure/logger');
14
14
  var msalCommon = require('@azure/msal-common');
15
15
  var uuid = require('uuid');
16
16
  var fs = require('fs');
@@ -18,8 +18,10 @@ var fs__default = _interopDefault(fs);
18
18
  var os = _interopDefault(require('os'));
19
19
  var path = _interopDefault(require('path'));
20
20
  var child_process = require('child_process');
21
+ var child_process__default = _interopDefault(child_process);
21
22
  var crypto = require('crypto');
22
- var qs = _interopDefault(require('qs'));
23
+ var util = require('util');
24
+ var https = _interopDefault(require('https'));
23
25
  var http = _interopDefault(require('http'));
24
26
  var open = _interopDefault(require('open'));
25
27
  var stoppable = _interopDefault(require('stoppable'));
@@ -149,7 +151,7 @@ const AggregateAuthenticationErrorName = "AggregateAuthenticationError";
149
151
  class AggregateAuthenticationError extends Error {
150
152
  constructor(errors, errorMessage) {
151
153
  const errorDetail = errors.join("\n");
152
- super(`${errorMessage}\n\n${errorDetail}`);
154
+ super(`${errorMessage}\n${errorDetail}`);
153
155
  this.errors = errors;
154
156
  // Ensure that this type reports the correct name
155
157
  this.name = AggregateAuthenticationErrorName;
@@ -165,6 +167,21 @@ function convertOAuthErrorResponseToErrorResponse(errorBody) {
165
167
  traceId: errorBody.trace_id
166
168
  };
167
169
  }
170
+ /**
171
+ * Error used to enforce authentication after trying to retrieve a token silently.
172
+ */
173
+ class AuthenticationRequiredError extends Error {
174
+ constructor(
175
+ /**
176
+ * 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.
177
+ */
178
+ options) {
179
+ super(options.message);
180
+ this.scopes = options.scopes;
181
+ this.getTokenOptions = options.getTokenOptions;
182
+ this.name = "AuthenticationRequiredError";
183
+ }
184
+ }
168
185
 
169
186
  // Copyright (c) Microsoft Corporation.
170
187
  // Licensed under the MIT license.
@@ -183,7 +200,7 @@ function getIdentityTokenEndpointSuffix(tenantId) {
183
200
  * @internal
184
201
  */
185
202
  const createSpan = coreTracing.createSpanFunction({
186
- packagePrefix: "Azure.Identity",
203
+ packagePrefix: "",
187
204
  namespace: "Microsoft.AAD"
188
205
  });
189
206
  /**
@@ -224,7 +241,7 @@ async function trace(operationName, options, fn, createSpanFn = createSpan) {
224
241
  /**
225
242
  * The AzureLogger used for all clients within the identity package
226
243
  */
227
- const logger = logger$h.createClientLogger("identity");
244
+ const logger = logger$k.createClientLogger("identity");
228
245
  /**
229
246
  * 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.
230
247
  * @param supportedEnvVars - List of environment variable names
@@ -315,7 +332,7 @@ function getIdentityClientAuthorityHost(options) {
315
332
  class IdentityClient extends coreClient.ServiceClient {
316
333
  constructor(options) {
317
334
  var _a;
318
- const packageDetails = `azsdk-js-identity/2.0.0-beta.5`;
335
+ const packageDetails = `azsdk-js-identity/2.0.1`;
319
336
  const userAgentPrefix = ((_a = options === null || options === void 0 ? void 0 : options.userAgentOptions) === null || _a === void 0 ? void 0 : _a.userAgentPrefix)
320
337
  ? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
321
338
  : `${packageDetails}`;
@@ -359,7 +376,6 @@ class IdentityClient extends coreClient.ServiceClient {
359
376
  }
360
377
  }
361
378
  async refreshAccessToken(tenantId, clientId, scopes, refreshToken, clientSecret, expiresOnParser, options) {
362
- var _a, _b;
363
379
  if (refreshToken === undefined) {
364
380
  return null;
365
381
  }
@@ -386,10 +402,7 @@ class IdentityClient extends coreClient.ServiceClient {
386
402
  Accept: "application/json",
387
403
  "Content-Type": "application/x-www-form-urlencoded"
388
404
  }),
389
- tracingOptions: {
390
- spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
391
- tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
392
- }
405
+ tracingOptions: updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions
393
406
  });
394
407
  const response = await this.sendTokenRequest(request, expiresOnParser);
395
408
  logger.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
@@ -515,28 +528,6 @@ function resolveTenantId(logger, tenantId, clientId) {
515
528
  return "organizations";
516
529
  }
517
530
 
518
- // Copyright (c) Microsoft Corporation.
519
- // Licensed under the MIT license.
520
- /**
521
- * Error used to enforce authentication after trying to retrieve a token silently.
522
- */
523
- class AuthenticationRequiredError extends Error {
524
- constructor(
525
- /**
526
- * The list of scopes for which the token will have access.
527
- */
528
- scopes,
529
- /**
530
- * The options used to configure the getToken request.
531
- */
532
- getTokenOptions = {}, message) {
533
- super(message);
534
- this.scopes = scopes;
535
- this.getTokenOptions = getTokenOptions;
536
- this.name = "AuthenticationRequiredError";
537
- }
538
- }
539
-
540
531
  // Copyright (c) Microsoft Corporation.
541
532
  /**
542
533
  * Latest AuthenticationRecord version
@@ -550,7 +541,11 @@ const LatestAuthenticationRecordVersion = "1.0";
550
541
  function ensureValidMsalToken(scopes, logger, msalToken, getTokenOptions) {
551
542
  const error = (message) => {
552
543
  logger.getToken.info(message);
553
- return new AuthenticationRequiredError(Array.isArray(scopes) ? scopes : [scopes], getTokenOptions, message);
544
+ return new AuthenticationRequiredError({
545
+ scopes: Array.isArray(scopes) ? scopes : [scopes],
546
+ getTokenOptions,
547
+ message
548
+ });
554
549
  };
555
550
  if (!msalToken) {
556
551
  throw error("No response");
@@ -678,7 +673,7 @@ class MsalBaseUtilities {
678
673
  error.name === "AbortError") {
679
674
  return error;
680
675
  }
681
- return new AuthenticationRequiredError(scopes, getTokenOptions, error.message);
676
+ return new AuthenticationRequiredError({ scopes, getTokenOptions, message: error.message });
682
677
  }
683
678
  }
684
679
  // transformations.ts
@@ -742,6 +737,40 @@ function deserializeAuthenticationRecord(serializedRecord) {
742
737
  }
743
738
 
744
739
  // Copyright (c) Microsoft Corporation.
740
+ // Licensed under the MIT license.
741
+ /**
742
+ * @internal
743
+ */
744
+ const multiTenantDisabledErrorMessage = "A getToken request was attempted with a tenant different than the tenant configured at the initialization of the credential, but multi-tenant authentication has been disabled by the environment variable AZURE_IDENTITY_DISABLE_MULTITENANTAUTH.";
745
+ /**
746
+ * @internal
747
+ */
748
+ const multiTenantADFSErrorMessage = "A new tenant Id can't be assigned through the GetTokenOptions when a credential has been originally configured to use the tenant `adfs`.";
749
+ /**
750
+ * Of getToken contains a tenantId, this functions allows picking this tenantId as the appropriate for authentication,
751
+ * unless multitenant authentication has been disabled through the AZURE_IDENTITY_DISABLE_MULTITENANTAUTH (on Node.js),
752
+ * or unless the original tenant Id is `adfs`.
753
+ * @internal
754
+ */
755
+ function processMultiTenantRequest(tenantId, getTokenOptions) {
756
+ if (!(getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId)) {
757
+ return tenantId;
758
+ }
759
+ if (process.env.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH) {
760
+ throw new Error(multiTenantDisabledErrorMessage);
761
+ }
762
+ if (tenantId === "adfs") {
763
+ throw new Error(multiTenantADFSErrorMessage);
764
+ }
765
+ return getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId;
766
+ }
767
+
768
+ // Copyright (c) Microsoft Corporation.
769
+ // Licensed under the MIT license.
770
+ /**
771
+ * Helps specify a regional authority, or "AutoDiscoverRegion" to auto-detect the region.
772
+ */
773
+ var RegionalAuthority;
745
774
  (function (RegionalAuthority) {
746
775
  /** Instructs MSAL to attempt to discover the region */
747
776
  RegionalAuthority["AutoDiscoverRegion"] = "AutoDiscoverRegion";
@@ -849,31 +878,7 @@ function deserializeAuthenticationRecord(serializedRecord) {
849
878
  RegionalAuthority["GovernmentUSDodEast"] = "usdodeast";
850
879
  /** Uses the {@link RegionalAuthority} for the Azure 'usdodcentral' region. */
851
880
  RegionalAuthority["GovernmentUSDodCentral"] = "usdodcentral";
852
- })(exports.RegionalAuthority || (exports.RegionalAuthority = {}));
853
-
854
- // Copyright (c) Microsoft Corporation.
855
- // Licensed under the MIT license.
856
- /**
857
- * @internal
858
- */
859
- const multiTenantErrorMessage = "A getToken request was attempted with a tenant different than the tenant configured at the initialization of the credential, but multi-tenant authentication was not enabled in this credential instance.";
860
- /**
861
- * Verifies whether locally assigned tenants are equal to tenants received through getToken.
862
- * Returns the appropriate tenant.
863
- * @internal
864
- */
865
- function processMultiTenantRequest(tenantId, allowMultiTenantAuthentication, getTokenOptions) {
866
- if (!allowMultiTenantAuthentication &&
867
- (getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId) &&
868
- tenantId &&
869
- getTokenOptions.tenantId !== tenantId) {
870
- throw new Error(multiTenantErrorMessage);
871
- }
872
- if (allowMultiTenantAuthentication && (getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId)) {
873
- return getTokenOptions.tenantId;
874
- }
875
- return tenantId;
876
- }
881
+ })(RegionalAuthority || (RegionalAuthority = {}));
877
882
 
878
883
  // Copyright (c) Microsoft Corporation.
879
884
  /**
@@ -906,17 +911,21 @@ class MsalNode extends MsalBaseUtilities {
906
911
  this.requiresConfidential = false;
907
912
  this.msalConfig = this.defaultNodeMsalConfig(options);
908
913
  this.tenantId = resolveTenantId(options.logger, options.tenantId, options.clientId);
909
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
910
914
  this.clientId = this.msalConfig.auth.clientId;
911
915
  // If persistence has been configured
912
916
  if (persistenceProvider !== undefined && ((_a = options.tokenCachePersistenceOptions) === null || _a === void 0 ? void 0 : _a.enabled)) {
913
917
  this.createCachePlugin = () => persistenceProvider(options.tokenCachePersistenceOptions);
914
918
  }
915
919
  else if ((_b = options.tokenCachePersistenceOptions) === null || _b === void 0 ? void 0 : _b.enabled) {
916
- throw new Error("Persistent token caching was requested, but no persistence provider was configured (do you need to use the `@azure/identity-cache-persistence` package?)");
920
+ throw new Error([
921
+ "Persistent token caching was requested, but no persistence provider was configured.",
922
+ "You must install the identity-cache-persistence plugin package (`npm install --save @azure/identity-cache-persistence`)",
923
+ "and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
924
+ "`useIdentityPlugin(cachePersistencePlugin)` before using `tokenCachePersistenceOptions`."
925
+ ].join(" "));
917
926
  }
918
927
  this.azureRegion = (_c = options.regionalAuthority) !== null && _c !== void 0 ? _c : process.env.AZURE_REGIONAL_AUTHORITY_NAME;
919
- if (this.azureRegion === exports.RegionalAuthority.AutoDiscoverRegion) {
928
+ if (this.azureRegion === RegionalAuthority.AutoDiscoverRegion) {
920
929
  this.azureRegion = "AUTO_DISCOVER";
921
930
  }
922
931
  }
@@ -1032,7 +1041,11 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
1032
1041
  var _a, _b;
1033
1042
  await this.getActiveAccount();
1034
1043
  if (!this.account) {
1035
- throw new AuthenticationRequiredError(scopes, options);
1044
+ throw new AuthenticationRequiredError({
1045
+ scopes,
1046
+ getTokenOptions: options,
1047
+ message: "Silent authentication failed. We couldn't retrieve an active account from the cache."
1048
+ });
1036
1049
  }
1037
1050
  const silentRequest = {
1038
1051
  // To be able to re-use the account, the Token Cache must also have been provided.
@@ -1055,8 +1068,7 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
1055
1068
  * If disableAutomaticAuthentication is sent through the constructor, it will prevent MSAL from requesting the user input.
1056
1069
  */
1057
1070
  async getToken(scopes, options = {}) {
1058
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
1059
- this.tenantId;
1071
+ const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
1060
1072
  options.authority = getAuthority(tenantId, this.authorityHost);
1061
1073
  options.correlationId = (options === null || options === void 0 ? void 0 : options.correlationId) || this.generateUuid();
1062
1074
  await this.init(options);
@@ -1068,7 +1080,11 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
1068
1080
  throw err;
1069
1081
  }
1070
1082
  if (options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication) {
1071
- throw new AuthenticationRequiredError(scopes, options, "Automatic authentication has been disabled. You may call the authentication() method.");
1083
+ throw new AuthenticationRequiredError({
1084
+ scopes,
1085
+ getTokenOptions: options,
1086
+ message: "Automatic authentication has been disabled. You may call the authentication() method."
1087
+ });
1072
1088
  }
1073
1089
  this.logger.info(`Silent authentication failed, falling back to interactive method.`);
1074
1090
  return this.doGetToken(scopes, options);
@@ -1137,7 +1153,7 @@ function getPropertyFromVSCode(property) {
1137
1153
  }
1138
1154
  }
1139
1155
  /**
1140
- * Connect to Azure using the credential provided by the VSCode extension 'Azure Account'.
1156
+ * Connects to Azure using the credential provided by the VSCode extension 'Azure Account'.
1141
1157
  * Once the user has logged in via the extension, this credential can share the same refresh token
1142
1158
  * that is cached by the extension.
1143
1159
  */
@@ -1145,6 +1161,11 @@ class VisualStudioCodeCredential {
1145
1161
  /**
1146
1162
  * Creates an instance of VisualStudioCodeCredential to use for automatically authenticating via VSCode.
1147
1163
  *
1164
+ * **Note**: `VisualStudioCodeCredential` is provided by a plugin package:
1165
+ * `@azure/identity-vscode`. If this package is not installed and registered
1166
+ * using the plugin API (`useIdentityPlugin`), then authentication using
1167
+ * `VisualStudioCodeCredential` will not be available.
1168
+ *
1148
1169
  * @param options - Options for configuring the client which makes the authentication request.
1149
1170
  */
1150
1171
  constructor(options) {
@@ -1161,7 +1182,6 @@ class VisualStudioCodeCredential {
1161
1182
  else {
1162
1183
  this.tenantId = CommonTenantId;
1163
1184
  }
1164
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
1165
1185
  checkUnsupportedTenant(this.tenantId);
1166
1186
  }
1167
1187
  /**
@@ -1195,10 +1215,14 @@ class VisualStudioCodeCredential {
1195
1215
  async getToken(scopes, options) {
1196
1216
  var _a, _b;
1197
1217
  await this.prepareOnce();
1198
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
1199
- this.tenantId;
1218
+ const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
1200
1219
  if (findCredentials === undefined) {
1201
- throw new CredentialUnavailableError("No implementation of VisualStudioCodeCredential is available (do you need to install and use the `@azure/identity-vscode` extension package?)");
1220
+ throw new CredentialUnavailableError([
1221
+ "No implementation of `VisualStudioCodeCredential` is available.",
1222
+ "You must install the identity-vscode plugin package (`npm install --save-dev @azure/identity-vscode`)",
1223
+ "and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
1224
+ "`useIdentityPlugin(vsCodePlugin)` before creating a `VisualStudioCodeCredential`."
1225
+ ].join(" "));
1202
1226
  }
1203
1227
  let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
1204
1228
  // Check to make sure the scope we get back is a valid scope
@@ -1228,13 +1252,13 @@ class VisualStudioCodeCredential {
1228
1252
  return tokenResponse.accessToken;
1229
1253
  }
1230
1254
  else {
1231
- const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Have you connected using the 'Azure Account' extension recently?");
1255
+ 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/visualstudiocodecredential/troubleshoot.");
1232
1256
  logger$1.getToken.info(formatError(scopes, error));
1233
1257
  throw error;
1234
1258
  }
1235
1259
  }
1236
1260
  else {
1237
- const error = new CredentialUnavailableError("Could not retrieve the token associated with Visual Studio Code. Did you connect using the 'Azure Account' extension?");
1261
+ 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/visualstudiocodecredential/troubleshoot.");
1238
1262
  logger$1.getToken.info(formatError(scopes, error));
1239
1263
  throw error;
1240
1264
  }
@@ -1243,17 +1267,17 @@ class VisualStudioCodeCredential {
1243
1267
 
1244
1268
  // Copyright (c) Microsoft Corporation.
1245
1269
  /**
1246
- * The context passed to an Identity Extension. This contains objects that
1247
- * extensions can use to set backend implementations.
1270
+ * The context passed to an Identity plugin. This contains objects that
1271
+ * plugins can use to set backend implementations.
1248
1272
  * @internal
1249
1273
  */
1250
- const extensionContext = {
1274
+ const pluginContext = {
1251
1275
  cachePluginControl: msalNodeFlowCacheControl,
1252
1276
  vsCodeCredentialControl: vsCodeCredentialControl
1253
1277
  };
1254
1278
  /**
1255
- * Extend Azure Identity with additional functionality. Pass an extension from
1256
- * an extension package, such as:
1279
+ * Extend Azure Identity with additional functionality. Pass a plugin from
1280
+ * a plugin package, such as:
1257
1281
  *
1258
1282
  * - `@azure/identity-cache-persistence`: provides persistent token caching
1259
1283
  * - `@azure/identity-vscode`: provides the dependencies of
@@ -1262,12 +1286,12 @@ const extensionContext = {
1262
1286
  * Example:
1263
1287
  *
1264
1288
  * ```javascript
1265
- * import { cachePersistenceExtension } from "@azure/identity-cache-persistence";
1289
+ * import { cachePersistencePlugin } from "@azure/identity-cache-persistence";
1266
1290
  *
1267
- * import { useIdentityExtension, DefaultAzureCredential } from "@azure/identity";
1268
- * useIdentityExtension(persistence);
1291
+ * import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
1292
+ * useIdentityPlugin(cachePersistencePlugin);
1269
1293
  *
1270
- * // The extension has the capability to extend `DefaultAzureCredential` and to
1294
+ * // The plugin has the capability to extend `DefaultAzureCredential` and to
1271
1295
  * // add middleware to the underlying credentials, such as persistence.
1272
1296
  * const credential = new DefaultAzureCredential({
1273
1297
  * tokenCachePersistenceOptions: {
@@ -1276,10 +1300,10 @@ const extensionContext = {
1276
1300
  * });
1277
1301
  * ```
1278
1302
  *
1279
- * @param extension - the extension to register
1303
+ * @param plugin - the plugin to register
1280
1304
  */
1281
- function useIdentityExtension(extension) {
1282
- extension(extensionContext);
1305
+ function useIdentityPlugin(plugin) {
1306
+ plugin(pluginContext);
1283
1307
  }
1284
1308
 
1285
1309
  // Copyright (c) Microsoft Corporation.
@@ -1327,12 +1351,13 @@ class ChainedTokenCredential {
1327
1351
  */
1328
1352
  async getToken(scopes, options) {
1329
1353
  let token = null;
1354
+ let successfulCredentialName = "";
1330
1355
  const errors = [];
1331
- const { span, updatedOptions } = createSpan("ChainedTokenCredential-getToken", options);
1356
+ const { span, updatedOptions } = createSpan("ChainedTokenCredential.getToken", options);
1332
1357
  for (let i = 0; i < this._sources.length && token === null; i++) {
1333
1358
  try {
1334
1359
  token = await this._sources[i].getToken(scopes, updatedOptions);
1335
- this.selectedCredential = this._sources[i];
1360
+ successfulCredentialName = this._sources[i].constructor.name;
1336
1361
  }
1337
1362
  catch (err) {
1338
1363
  if (err.name === "CredentialUnavailableError" ||
@@ -1346,7 +1371,7 @@ class ChainedTokenCredential {
1346
1371
  }
1347
1372
  }
1348
1373
  if (!token && errors.length > 0) {
1349
- const err = new AggregateAuthenticationError(errors);
1374
+ const err = new AggregateAuthenticationError(errors, "ChainedTokenCredential authentication failed.");
1350
1375
  span.setStatus({
1351
1376
  code: coreTracing.SpanStatusCode.ERROR,
1352
1377
  message: err.message
@@ -1355,7 +1380,7 @@ class ChainedTokenCredential {
1355
1380
  throw err;
1356
1381
  }
1357
1382
  span.end();
1358
- logger$2.getToken.info(`Result for ${this.selectedCredential.constructor.name}: ${formatSuccess(scopes)}`);
1383
+ logger$2.getToken.info(`Result for ${successfulCredentialName}: ${formatSuccess(scopes)}`);
1359
1384
  if (token === null) {
1360
1385
  throw new CredentialUnavailableError("Failed to retrieve a valid token");
1361
1386
  }
@@ -1415,15 +1440,15 @@ const cliCredentialInternals = {
1415
1440
  }
1416
1441
  return new Promise((resolve, reject) => {
1417
1442
  try {
1418
- child_process.execFile("az", [
1443
+ child_process__default.execFile("az", [
1419
1444
  "account",
1420
1445
  "get-access-token",
1421
1446
  "--output",
1422
1447
  "json",
1423
1448
  "--resource",
1424
- ...tenantSection,
1425
- resource
1426
- ], { cwd: cliCredentialInternals.getSafeWorkingDir() }, (error, stdout, stderr) => {
1449
+ resource,
1450
+ ...tenantSection
1451
+ ], { cwd: cliCredentialInternals.getSafeWorkingDir(), shell: true }, (error, stdout, stderr) => {
1427
1452
  resolve({ stdout: stdout, stderr: stderr, error });
1428
1453
  });
1429
1454
  }
@@ -1439,18 +1464,18 @@ const logger$3 = credentialLogger("AzureCliCredential");
1439
1464
  * via the Azure CLI ('az') commandline tool.
1440
1465
  * To do so, it will read the user access token and expire time
1441
1466
  * with Azure CLI command "az account get-access-token".
1442
- * To be able to use this credential, ensure that you have already logged
1443
- * in via the 'az' tool using the command "az login" from the commandline.
1444
1467
  */
1445
1468
  class AzureCliCredential {
1446
1469
  /**
1447
1470
  * Creates an instance of the {@link AzureCliCredential}.
1448
1471
  *
1472
+ * To use this credential, ensure that you have already logged
1473
+ * in via the 'az' tool using the command "az login" from the commandline.
1474
+ *
1449
1475
  * @param options - Options, to optionally allow multi-tenant requests.
1450
1476
  */
1451
1477
  constructor(options) {
1452
1478
  this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
1453
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
1454
1479
  }
1455
1480
  /**
1456
1481
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -1461,7 +1486,7 @@ class AzureCliCredential {
1461
1486
  * TokenCredential implementation might make.
1462
1487
  */
1463
1488
  async getToken(scopes, options) {
1464
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options);
1489
+ const tenantId = processMultiTenantRequest(this.tenantId, options);
1465
1490
  if (tenantId) {
1466
1491
  checkTenantId(logger$3, tenantId);
1467
1492
  }
@@ -1470,7 +1495,7 @@ class AzureCliCredential {
1470
1495
  ensureValidScope(scope, logger$3);
1471
1496
  const resource = getScopeResource(scope);
1472
1497
  let responseData = "";
1473
- const { span } = createSpan("AzureCliCredential-getToken", options);
1498
+ const { span } = createSpan("AzureCliCredential.getToken", options);
1474
1499
  try {
1475
1500
  const obj = await cliCredentialInternals.getAzureCliAccessToken(resource, tenantId);
1476
1501
  if (obj.stderr) {
@@ -1587,7 +1612,8 @@ const powerShellErrors = {
1587
1612
  */
1588
1613
  const powerShellPublicErrorMessages = {
1589
1614
  login: "Please run 'Connect-AzAccount' from PowerShell to authenticate before using this credential.",
1590
- installed: `The 'Az.Account' module >= 2.2.0 is not installed. Install the Azure Az PowerShell module with: "Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force".`
1615
+ installed: `The 'Az.Account' module >= 2.2.0 is not installed. Install the Azure Az PowerShell module with: "Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force".`,
1616
+ troubleshoot: `To troubleshoot, visit https://aka.ms/azsdk/js/identity/powershellcredential/troubleshoot.`
1591
1617
  };
1592
1618
  // PowerShell Azure User not logged in error check.
1593
1619
  const isLoginError = (err) => err.message.match(`(.*)${powerShellErrors.login}(.*)`);
@@ -1606,22 +1632,21 @@ if (isWindows) {
1606
1632
  * This credential will use the currently logged-in user information from the
1607
1633
  * Azure PowerShell module. To do so, it will read the user access token and
1608
1634
  * expire time with Azure PowerShell command `Get-AzAccessToken -ResourceUrl {ResourceScope}`
1609
- *
1610
- * To be able to use this credential:
1611
- * - Install the Azure Az PowerShell module with:
1612
- * `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
1613
- * - You have already logged in to Azure PowerShell using the command
1614
- * `Connect-AzAccount` from the command line.
1615
1635
  */
1616
1636
  class AzurePowerShellCredential {
1617
1637
  /**
1618
- * Creates an instance of the {@link AzurePowershellCredential}.
1638
+ * Creates an instance of the {@link AzurePowerShellCredential}.
1639
+ *
1640
+ * To use this credential:
1641
+ * - Install the Azure Az PowerShell module with:
1642
+ * `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
1643
+ * - You have already logged in to Azure PowerShell using the command
1644
+ * `Connect-AzAccount` from the command line.
1619
1645
  *
1620
1646
  * @param options - Options, to optionally allow multi-tenant requests.
1621
1647
  */
1622
1648
  constructor(options) {
1623
1649
  this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
1624
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
1625
1650
  }
1626
1651
  /**
1627
1652
  * Gets the access token from Azure PowerShell
@@ -1662,7 +1687,7 @@ class AzurePowerShellCredential {
1662
1687
  throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
1663
1688
  }
1664
1689
  }
1665
- throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system.`);
1690
+ throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
1666
1691
  }
1667
1692
  /**
1668
1693
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -1673,7 +1698,7 @@ class AzurePowerShellCredential {
1673
1698
  */
1674
1699
  async getToken(scopes, options = {}) {
1675
1700
  return trace(`${this.constructor.name}.getToken`, options, async () => {
1676
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options);
1701
+ const tenantId = processMultiTenantRequest(this.tenantId, options);
1677
1702
  if (tenantId) {
1678
1703
  checkTenantId(logger$4, tenantId);
1679
1704
  }
@@ -1700,7 +1725,7 @@ class AzurePowerShellCredential {
1700
1725
  logger$4.getToken.info(formatError(scope, error));
1701
1726
  throw error;
1702
1727
  }
1703
- const error = new CredentialUnavailableError(err);
1728
+ const error = new CredentialUnavailableError(`${err}. ${powerShellPublicErrorMessages.troubleshoot}`);
1704
1729
  logger$4.getToken.info(formatError(scope, error));
1705
1730
  throw error;
1706
1731
  }
@@ -1759,6 +1784,9 @@ class ClientSecretCredential {
1759
1784
  * @param options - Options for configuring the client which makes the authentication request.
1760
1785
  */
1761
1786
  constructor(tenantId, clientId, clientSecret, options = {}) {
1787
+ if (!tenantId || !clientId || !clientSecret) {
1788
+ throw new Error("ClientSecretCredential: tenantId, clientId, and clientSecret are required parameters. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
1789
+ }
1762
1790
  this.msalFlow = new MsalClientSecret(Object.assign(Object.assign({}, options), { logger: logger$5,
1763
1791
  clientId,
1764
1792
  tenantId,
@@ -1781,6 +1809,41 @@ class ClientSecretCredential {
1781
1809
  }
1782
1810
 
1783
1811
  // Copyright (c) Microsoft Corporation.
1812
+ const readFileAsync = util.promisify(fs.readFile);
1813
+ /**
1814
+ * Tries to asynchronously load a certificate from the given path.
1815
+ *
1816
+ * @param configuration - Either the PEM value or the path to the certificate.
1817
+ * @param sendCertificateChain - Option to include x5c header for SubjectName and Issuer name authorization.
1818
+ * @returns - The certificate parts, or `undefined` if the certificate could not be loaded.
1819
+ * @internal
1820
+ */
1821
+ async function parseCertificate(configuration, sendCertificateChain) {
1822
+ const certificateParts = {};
1823
+ certificateParts.certificateContents =
1824
+ configuration.certificate || (await readFileAsync(configuration.certificatePath, "utf8"));
1825
+ if (sendCertificateChain) {
1826
+ certificateParts.x5c = certificateParts.certificateContents;
1827
+ }
1828
+ const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
1829
+ const publicKeys = [];
1830
+ // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
1831
+ let match;
1832
+ do {
1833
+ match = certificatePattern.exec(certificateParts.certificateContents);
1834
+ if (match) {
1835
+ publicKeys.push(match[3]);
1836
+ }
1837
+ } while (match);
1838
+ if (publicKeys.length === 0) {
1839
+ throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
1840
+ }
1841
+ certificateParts.thumbprint = crypto.createHash("sha1")
1842
+ .update(Buffer.from(publicKeys[0], "base64"))
1843
+ .digest("hex")
1844
+ .toUpperCase();
1845
+ return certificateParts;
1846
+ }
1784
1847
  /**
1785
1848
  * MSAL client certificate client. Calls to MSAL's confidential application's `acquireTokenByClientCredential` during `doGetToken`.
1786
1849
  * @internal
@@ -1789,40 +1852,24 @@ class MsalClientCertificate extends MsalNode {
1789
1852
  constructor(options) {
1790
1853
  super(options);
1791
1854
  this.requiresConfidential = true;
1855
+ this.configuration = options.configuration;
1792
1856
  this.sendCertificateChain = options.sendCertificateChain;
1793
- const parts = this.parseCertificate(options.certificatePath);
1794
- this.msalConfig.auth.clientCertificate = {
1795
- thumbprint: parts.thumbprint,
1796
- privateKey: parts.certificateContents,
1797
- x5c: parts.x5c
1798
- };
1799
1857
  }
1800
- parseCertificate(certificatePath) {
1801
- const certificateParts = {};
1802
- certificateParts.certificateContents = fs.readFileSync(certificatePath, "utf8");
1803
- if (this.sendCertificateChain) {
1804
- certificateParts.x5c = certificateParts.certificateContents;
1805
- }
1806
- const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
1807
- const publicKeys = [];
1808
- // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
1809
- let match;
1810
- do {
1811
- match = certificatePattern.exec(certificateParts.certificateContents);
1812
- if (match) {
1813
- publicKeys.push(match[3]);
1814
- }
1815
- } while (match);
1816
- if (publicKeys.length === 0) {
1817
- const error = new Error("The file at the specified path does not contain a PEM-encoded certificate.");
1858
+ // Changing the MSAL configuration asynchronously
1859
+ async init(options) {
1860
+ try {
1861
+ const parts = await parseCertificate(this.configuration, this.sendCertificateChain);
1862
+ this.msalConfig.auth.clientCertificate = {
1863
+ thumbprint: parts.thumbprint,
1864
+ privateKey: parts.certificateContents,
1865
+ x5c: parts.x5c
1866
+ };
1867
+ }
1868
+ catch (error) {
1818
1869
  this.logger.info(formatError("", error));
1819
1870
  throw error;
1820
1871
  }
1821
- certificateParts.thumbprint = crypto.createHash("sha1")
1822
- .update(Buffer.from(publicKeys[0], "base64"))
1823
- .digest("hex")
1824
- .toUpperCase();
1825
- return certificateParts;
1872
+ return super.init(options);
1826
1873
  }
1827
1874
  async doGetToken(scopes, options = {}) {
1828
1875
  try {
@@ -1844,7 +1891,8 @@ class MsalClientCertificate extends MsalNode {
1844
1891
  }
1845
1892
 
1846
1893
  // Copyright (c) Microsoft Corporation.
1847
- const logger$6 = credentialLogger("ClientCertificateCredential");
1894
+ const credentialName = "ClientCertificateCredential";
1895
+ const logger$6 = credentialLogger(credentialName);
1848
1896
  /**
1849
1897
  * Enables authentication to Azure Active Directory using a PEM-encoded
1850
1898
  * certificate that is assigned to an App Registration. More information
@@ -1854,17 +1902,22 @@ const logger$6 = credentialLogger("ClientCertificateCredential");
1854
1902
  *
1855
1903
  */
1856
1904
  class ClientCertificateCredential {
1857
- /**
1858
- * Creates an instance of the ClientCertificateCredential with the details
1859
- * needed to authenticate against Azure Active Directory with a certificate.
1860
- *
1861
- * @param tenantId - The Azure Active Directory tenant (directory) ID.
1862
- * @param clientId - The client (application) ID of an App Registration in the tenant.
1863
- * @param certificatePath - The path to a PEM-encoded public/private key certificate on the filesystem.
1864
- * @param options - Options for configuring the client which makes the authentication request.
1865
- */
1866
- constructor(tenantId, clientId, certificatePath, options = {}) {
1867
- this.msalFlow = new MsalClientCertificate(Object.assign(Object.assign({}, options), { certificatePath,
1905
+ constructor(tenantId, clientId, certificatePathOrConfiguration, options = {}) {
1906
+ if (!tenantId || !clientId) {
1907
+ throw new Error(`${credentialName}: tenantId and clientId are required parameters.`);
1908
+ }
1909
+ const configuration = Object.assign({}, (typeof certificatePathOrConfiguration === "string"
1910
+ ? {
1911
+ certificatePath: certificatePathOrConfiguration
1912
+ }
1913
+ : certificatePathOrConfiguration));
1914
+ if (!configuration || !(configuration.certificate || configuration.certificatePath)) {
1915
+ throw new Error(`${credentialName}: Provide either a PEM certificate in string form, or the path to that certificate in the filesystem. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
1916
+ }
1917
+ if (configuration.certificate && configuration.certificatePath) {
1918
+ throw new Error(`${credentialName}: To avoid unexpected behaviors, providing both the contents of a PEM certificate and the path to a PEM certificate is forbidden. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
1919
+ }
1920
+ this.msalFlow = new MsalClientCertificate(Object.assign(Object.assign({}, options), { configuration,
1868
1921
  logger: logger$6,
1869
1922
  clientId,
1870
1923
  tenantId, sendCertificateChain: options.sendCertificateChain, tokenCredentialOptions: options }));
@@ -1878,7 +1931,7 @@ class ClientCertificateCredential {
1878
1931
  * TokenCredential implementation might make.
1879
1932
  */
1880
1933
  async getToken(scopes, options = {}) {
1881
- return trace(`${this.constructor.name}.getToken`, options, async (newOptions) => {
1934
+ return trace(`${credentialName}.getToken`, options, async (newOptions) => {
1882
1935
  const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
1883
1936
  return this.msalFlow.getToken(arrayScopes, newOptions);
1884
1937
  });
@@ -1922,8 +1975,6 @@ const logger$7 = credentialLogger("UsernamePasswordCredential");
1922
1975
  * trust so you should only use it when other, more secure credential
1923
1976
  * types can't be used.
1924
1977
  */
1925
- // We'll be using InteractiveCredential as the base of this class, which requires us to support authenticate(),
1926
- // to reduce the number of times we send the password over the network.
1927
1978
  class UsernamePasswordCredential {
1928
1979
  /**
1929
1980
  * Creates an instance of the UsernamePasswordCredential with the details
@@ -1937,6 +1988,9 @@ class UsernamePasswordCredential {
1937
1988
  * @param options - Options for configuring the client which makes the authentication request.
1938
1989
  */
1939
1990
  constructor(tenantId, clientId, username, password, options = {}) {
1991
+ if (!tenantId || !clientId || !username || !password) {
1992
+ throw new Error("UsernamePasswordCredential: tenantId, clientId, username and password are required parameters. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
1993
+ }
1940
1994
  this.msalFlow = new MsalUsernamePassword(Object.assign(Object.assign({}, options), { logger: logger$7,
1941
1995
  clientId,
1942
1996
  tenantId,
@@ -1982,23 +2036,7 @@ const AllSupportedEnvironmentVariables = [
1982
2036
  const logger$8 = credentialLogger("EnvironmentCredential");
1983
2037
  /**
1984
2038
  * Enables authentication to Azure Active Directory using client secret
1985
- * details configured in the following environment variables:
1986
- *
1987
- * Required environment variables:
1988
- * - `AZURE_TENANT_ID`: The Azure Active Directory tenant (directory) ID.
1989
- * - `AZURE_CLIENT_ID`: The client (application) ID of an App Registration in the tenant.
1990
- *
1991
- * Environment variables used for client credential authentication:
1992
- * - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
1993
- * - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
1994
- *
1995
- * Alternatively, users can provide environment variables for username and password authentication:
1996
- * - `AZURE_USERNAME`: Username to authenticate with.
1997
- * - `AZURE_PASSWORD`: Password to authenticate with.
1998
- *
1999
- * This credential ultimately uses a {@link ClientSecretCredential} to
2000
- * perform the authentication using these details. Please consult the
2001
- * documentation of that class for more details.
2039
+ * details configured in environment variables
2002
2040
  */
2003
2041
  class EnvironmentCredential {
2004
2042
  /**
@@ -2038,7 +2076,7 @@ class EnvironmentCredential {
2038
2076
  const certificatePath = process.env.AZURE_CLIENT_CERTIFICATE_PATH;
2039
2077
  if (tenantId && clientId && certificatePath) {
2040
2078
  logger$8.info(`Invoking ClientCertificateCredential with tenant ID: ${tenantId}, clientId: ${clientId} and certificatePath: ${certificatePath}`);
2041
- this._credential = new ClientCertificateCredential(tenantId, clientId, certificatePath, options);
2079
+ this._credential = new ClientCertificateCredential(tenantId, clientId, { certificatePath }, options);
2042
2080
  return;
2043
2081
  }
2044
2082
  const username = process.env.AZURE_USERNAME;
@@ -2064,7 +2102,7 @@ class EnvironmentCredential {
2064
2102
  }
2065
2103
  catch (err) {
2066
2104
  const authenticationError = new AuthenticationError(400, {
2067
- error: "EnvironmentCredential authentication failed.",
2105
+ error: "EnvironmentCredential authentication failed. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.",
2068
2106
  error_description: err.message
2069
2107
  .toString()
2070
2108
  .split("More details:")
@@ -2074,7 +2112,7 @@ class EnvironmentCredential {
2074
2112
  throw authenticationError;
2075
2113
  }
2076
2114
  }
2077
- throw new CredentialUnavailableError("EnvironmentCredential is unavailable. No underlying credential could be used.");
2115
+ throw new CredentialUnavailableError("EnvironmentCredential is unavailable. No underlying credential could be used. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.");
2078
2116
  });
2079
2117
  }
2080
2118
  }
@@ -2086,13 +2124,22 @@ const imdsHost = "http://169.254.169.254";
2086
2124
  const imdsEndpointPath = "/metadata/identity/oauth2/token";
2087
2125
  const imdsApiVersion = "2018-02-01";
2088
2126
  const azureArcAPIVersion = "2019-11-01";
2127
+ const azureFabricVersion = "2019-07-01-preview";
2089
2128
 
2090
2129
  // Copyright (c) Microsoft Corporation.
2130
+ /**
2131
+ * Most MSIs send requests to the IMDS endpoint, or a similar endpoint. These are GET requests that require sending a `resource` parameter on the query.
2132
+ * This resource can be derived from the scopes received through the getToken call, as long as only one scope is received.
2133
+ * Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case.
2134
+ *
2135
+ * For that reason, when we encounter multiple scopes, we return undefined.
2136
+ * It's up to the individual MSI implementations to throw the errors (which helps us provide less generic errors).
2137
+ */
2091
2138
  function mapScopesToResource(scopes) {
2092
2139
  let scope = "";
2093
2140
  if (Array.isArray(scopes)) {
2094
2141
  if (scopes.length !== 1) {
2095
- throw new Error("To convert to a resource string the specified array must be exactly length 1");
2142
+ return;
2096
2143
  }
2097
2144
  scope = scopes[0];
2098
2145
  }
@@ -2104,23 +2151,28 @@ function mapScopesToResource(scopes) {
2104
2151
  }
2105
2152
  return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
2106
2153
  }
2107
- async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}) {
2108
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal, tracingOptions: {
2109
- spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions,
2110
- tracingContext: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.tracingContext
2111
- } }, requestOptions), { allowInsecureConnection: true }));
2154
+ async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}, agent) {
2155
+ const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, requestOptions), { allowInsecureConnection: true }));
2156
+ if (agent) {
2157
+ request.agent = agent;
2158
+ }
2112
2159
  const tokenResponse = await identityClient.sendTokenRequest(request, expiresInParser);
2113
2160
  return (tokenResponse && tokenResponse.accessToken) || null;
2114
2161
  }
2115
2162
 
2116
2163
  // Copyright (c) Microsoft Corporation.
2117
- const logger$9 = credentialLogger("ManagedIdentityCredential - AppServiceMSI 2017");
2164
+ const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
2165
+ const logger$9 = credentialLogger(msiName);
2118
2166
  function expiresInParser(requestBody) {
2119
2167
  // Parse a date format like "06/20/2019 02:57:58 +00:00" and
2120
2168
  // convert it into a JavaScript-formatted date
2121
2169
  return Date.parse(requestBody.expires_on);
2122
2170
  }
2123
- function prepareRequestOptions(resource, clientId) {
2171
+ function prepareRequestOptions(scopes, clientId) {
2172
+ const resource = mapScopesToResource(scopes);
2173
+ if (!resource) {
2174
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
2175
+ }
2124
2176
  const queryParameters = {
2125
2177
  resource,
2126
2178
  "api-version": "2017-09-01"
@@ -2131,10 +2183,10 @@ function prepareRequestOptions(resource, clientId) {
2131
2183
  const query = new URLSearchParams(queryParameters);
2132
2184
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2133
2185
  if (!process.env.MSI_ENDPOINT) {
2134
- throw new Error("Missing environment variable: MSI_ENDPOINT");
2186
+ throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
2135
2187
  }
2136
2188
  if (!process.env.MSI_SECRET) {
2137
- throw new Error("Missing environment variable: MSI_SECRET");
2189
+ throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
2138
2190
  }
2139
2191
  return {
2140
2192
  url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
@@ -2146,25 +2198,36 @@ function prepareRequestOptions(resource, clientId) {
2146
2198
  };
2147
2199
  }
2148
2200
  const appServiceMsi2017 = {
2149
- async isAvailable() {
2201
+ async isAvailable(scopes) {
2202
+ const resource = mapScopesToResource(scopes);
2203
+ if (!resource) {
2204
+ logger$9.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
2205
+ return false;
2206
+ }
2150
2207
  const env = process.env;
2151
2208
  const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
2152
2209
  if (!result) {
2153
- logger$9.info("The Azure App Service MSI 2017 is unavailable.");
2210
+ logger$9.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
2154
2211
  }
2155
2212
  return result;
2156
2213
  },
2157
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2158
- logger$9.info(`Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
2159
- return msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, getTokenOptions);
2214
+ async getToken(configuration, getTokenOptions = {}) {
2215
+ const { identityClient, scopes, clientId } = configuration;
2216
+ logger$9.info(`${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
2217
+ return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
2160
2218
  }
2161
2219
  };
2162
2220
 
2163
2221
  // Copyright (c) Microsoft Corporation.
2164
- const logger$a = credentialLogger("ManagedIdentityCredential - CloudShellMSI");
2222
+ const msiName$1 = "ManagedIdentityCredential - CloudShellMSI";
2223
+ const logger$a = credentialLogger(msiName$1);
2165
2224
  // Cloud Shell MSI doesn't have a special expiresIn parser.
2166
2225
  const expiresInParser$1 = undefined;
2167
- function prepareRequestOptions$1(resource, clientId) {
2226
+ function prepareRequestOptions$1(scopes, clientId) {
2227
+ const resource = mapScopesToResource(scopes);
2228
+ if (!resource) {
2229
+ throw new Error(`${msiName$1}: Multiple scopes are not supported.`);
2230
+ }
2168
2231
  const body = {
2169
2232
  resource
2170
2233
  };
@@ -2173,12 +2236,13 @@ function prepareRequestOptions$1(resource, clientId) {
2173
2236
  }
2174
2237
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2175
2238
  if (!process.env.MSI_ENDPOINT) {
2176
- throw new Error("Missing environment variable: MSI_ENDPOINT");
2239
+ throw new Error(`${msiName$1}: Missing environment variable: MSI_ENDPOINT`);
2177
2240
  }
2241
+ const params = new URLSearchParams(body);
2178
2242
  return {
2179
2243
  url: process.env.MSI_ENDPOINT,
2180
2244
  method: "POST",
2181
- body: qs.stringify(body),
2245
+ body: params.toString(),
2182
2246
  headers: coreRestPipeline.createHttpHeaders({
2183
2247
  Accept: "application/json",
2184
2248
  Metadata: "true",
@@ -2187,53 +2251,77 @@ function prepareRequestOptions$1(resource, clientId) {
2187
2251
  };
2188
2252
  }
2189
2253
  const cloudShellMsi = {
2190
- async isAvailable() {
2254
+ async isAvailable(scopes) {
2255
+ const resource = mapScopesToResource(scopes);
2256
+ if (!resource) {
2257
+ logger$a.info(`${msiName$1}: Unavailable. Multiple scopes are not supported.`);
2258
+ return false;
2259
+ }
2191
2260
  const result = Boolean(process.env.MSI_ENDPOINT);
2192
2261
  if (!result) {
2193
- logger$a.info("The Azure Cloud Shell MSI is unavailable.");
2262
+ logger$a.info(`${msiName$1}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
2194
2263
  }
2195
2264
  return result;
2196
2265
  },
2197
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2198
- logger$a.info(`Using the endpoint coming form the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the Cloud Shell to proceed with the authentication.`);
2199
- return msiGenericGetToken(identityClient, prepareRequestOptions$1(resource, clientId), expiresInParser$1, getTokenOptions);
2266
+ async getToken(configuration, getTokenOptions = {}) {
2267
+ const { identityClient, scopes, clientId } = configuration;
2268
+ logger$a.info(`${msiName$1}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
2269
+ return msiGenericGetToken(identityClient, prepareRequestOptions$1(scopes, clientId), expiresInParser$1, getTokenOptions);
2200
2270
  }
2201
2271
  };
2202
2272
 
2203
2273
  // Copyright (c) Microsoft Corporation.
2204
- const logger$b = credentialLogger("ManagedIdentityCredential - IMDS");
2274
+ const msiName$2 = "ManagedIdentityCredential - IMDS";
2275
+ const logger$b = credentialLogger(msiName$2);
2205
2276
  function expiresInParser$2(requestBody) {
2206
2277
  if (requestBody.expires_on) {
2207
2278
  // Use the expires_on timestamp if it's available
2208
2279
  const expires = +requestBody.expires_on * 1000;
2209
- logger$b.info(`IMDS using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
2280
+ logger$b.info(`${msiName$2}: Using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
2210
2281
  return expires;
2211
2282
  }
2212
2283
  else {
2213
2284
  // If these aren't possible, use expires_in and calculate a timestamp
2214
2285
  const expires = Date.now() + requestBody.expires_in * 1000;
2215
- logger$b.info(`IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
2286
+ logger$b.info(`${msiName$2}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
2216
2287
  return expires;
2217
2288
  }
2218
2289
  }
2219
- function prepareRequestOptions$2(resource, clientId) {
2290
+ function prepareRequestOptions$2(scopes, clientId, options) {
2220
2291
  var _a;
2221
- const queryParameters = {
2222
- resource,
2223
- "api-version": imdsApiVersion
2224
- };
2225
- if (clientId) {
2226
- queryParameters.client_id = clientId;
2292
+ const resource = mapScopesToResource(scopes);
2293
+ if (!resource) {
2294
+ throw new Error(`${msiName$2}: Multiple scopes are not supported.`);
2295
+ }
2296
+ const { skipQuery, skipMetadataHeader } = options || {};
2297
+ let query = "";
2298
+ // Pod Identity will try to process this request even if the Metadata header is missing.
2299
+ // We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.
2300
+ if (!skipQuery) {
2301
+ const queryParameters = {
2302
+ resource,
2303
+ "api-version": imdsApiVersion
2304
+ };
2305
+ if (clientId) {
2306
+ queryParameters.client_id = clientId;
2307
+ }
2308
+ const params = new URLSearchParams(queryParameters);
2309
+ query = `?${params.toString()}`;
2227
2310
  }
2228
- const query = qs.stringify(queryParameters);
2229
2311
  const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
2312
+ const rawHeaders = {
2313
+ Accept: "application/json",
2314
+ Metadata: "true"
2315
+ };
2316
+ // Remove the Metadata header to invoke a request error from some IMDS endpoints.
2317
+ if (skipMetadataHeader) {
2318
+ delete rawHeaders.Metadata;
2319
+ }
2230
2320
  return {
2231
- url: `${url}?${query}`,
2321
+ // In this case, the `?` should be added in the "query" variable `skipQuery` is not set.
2322
+ url: `${url}${query}`,
2232
2323
  method: "GET",
2233
- headers: coreRestPipeline.createHttpHeaders({
2234
- Accept: "application/json",
2235
- Metadata: "true"
2236
- })
2324
+ headers: coreRestPipeline.createHttpHeaders(rawHeaders)
2237
2325
  };
2238
2326
  }
2239
2327
  // 800ms -> 1600ms -> 3200ms
@@ -2243,24 +2331,23 @@ const imdsMsiRetryConfig = {
2243
2331
  intervalIncrement: 2
2244
2332
  };
2245
2333
  const imdsMsi = {
2246
- async isAvailable(identityClient, resource, clientId, getTokenOptions) {
2334
+ async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
2247
2335
  var _a, _b;
2336
+ const resource = mapScopesToResource(scopes);
2337
+ if (!resource) {
2338
+ logger$b.info(`${msiName$2}: Unavailable. Multiple scopes are not supported.`);
2339
+ return false;
2340
+ }
2248
2341
  const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
2249
2342
  // if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
2250
2343
  if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
2251
2344
  return true;
2252
2345
  }
2253
- const requestOptions = prepareRequestOptions$2(resource, clientId);
2254
- // This will always be populated, but let's make TypeScript happy
2255
- if (requestOptions.headers) {
2256
- // Remove the Metadata header to invoke a request error from
2257
- // IMDS endpoint
2258
- requestOptions.headers.delete("Metadata");
2259
- }
2260
- requestOptions.tracingOptions = {
2261
- spanOptions: options.tracingOptions && options.tracingOptions.spanOptions,
2262
- tracingContext: options.tracingOptions && options.tracingOptions.tracingContext
2263
- };
2346
+ const requestOptions = prepareRequestOptions$2(resource, clientId, {
2347
+ skipMetadataHeader: true,
2348
+ skipQuery: true
2349
+ });
2350
+ requestOptions.tracingOptions = options.tracingOptions;
2264
2351
  try {
2265
2352
  // Create a request with a timeout since we expect that
2266
2353
  // not having a "Metadata" header should cause an error to be
@@ -2270,18 +2357,19 @@ const imdsMsi = {
2270
2357
  // This MSI uses the imdsEndpoint to get the token, which only uses http://
2271
2358
  request.allowInsecureConnection = true;
2272
2359
  try {
2273
- logger$b.info(`Pinging the Azure IMDS endpoint`);
2360
+ logger$b.info(`${msiName$2}: Pinging the Azure IMDS endpoint`);
2274
2361
  await identityClient.sendRequest(request);
2275
2362
  }
2276
2363
  catch (err) {
2277
2364
  if ((err.name === "RestError" && err.code === coreRestPipeline.RestError.REQUEST_SEND_ERROR) ||
2278
2365
  err.name === "AbortError" ||
2366
+ err.code === "ENETUNREACH" || // Network unreachable
2279
2367
  err.code === "ECONNREFUSED" || // connection refused
2280
2368
  err.code === "EHOSTDOWN" // host is down
2281
2369
  ) {
2282
2370
  // If the request failed, or Node.js was unable to establish a connection,
2283
2371
  // or the host was down, we'll assume the IMDS endpoint isn't available.
2284
- logger$b.info(`The Azure IMDS endpoint is unavailable`);
2372
+ logger$b.info(`${msiName$2}: The Azure IMDS endpoint is unavailable`);
2285
2373
  span.setStatus({
2286
2374
  code: coreTracing.SpanStatusCode.ERROR,
2287
2375
  message: err.message
@@ -2290,13 +2378,13 @@ const imdsMsi = {
2290
2378
  }
2291
2379
  }
2292
2380
  // If we received any response, the endpoint is available
2293
- logger$b.info(`The Azure IMDS endpoint is available`);
2381
+ logger$b.info(`${msiName$2}: The Azure IMDS endpoint is available`);
2294
2382
  return true;
2295
2383
  }
2296
2384
  catch (err) {
2297
2385
  // createWebResource failed.
2298
2386
  // This error should bubble up to the user.
2299
- logger$b.info(`Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
2387
+ logger$b.info(`${msiName$2}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
2300
2388
  span.setStatus({
2301
2389
  code: coreTracing.SpanStatusCode.ERROR,
2302
2390
  message: err.message
@@ -2307,12 +2395,13 @@ const imdsMsi = {
2307
2395
  span.end();
2308
2396
  }
2309
2397
  },
2310
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2311
- logger$b.info(`Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
2398
+ async getToken(configuration, getTokenOptions = {}) {
2399
+ const { identityClient, scopes, clientId } = configuration;
2400
+ logger$b.info(`${msiName$2}: Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
2312
2401
  let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
2313
2402
  for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
2314
2403
  try {
2315
- return await msiGenericGetToken(identityClient, prepareRequestOptions$2(resource, clientId), expiresInParser$2, getTokenOptions);
2404
+ return await msiGenericGetToken(identityClient, prepareRequestOptions$2(scopes, clientId), expiresInParser$2, getTokenOptions);
2316
2405
  }
2317
2406
  catch (error) {
2318
2407
  if (error.statusCode === 404) {
@@ -2323,15 +2412,20 @@ const imdsMsi = {
2323
2412
  throw error;
2324
2413
  }
2325
2414
  }
2326
- throw new AuthenticationError(404, `Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
2415
+ throw new AuthenticationError(404, `${msiName$2}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
2327
2416
  }
2328
2417
  };
2329
2418
 
2330
2419
  // Copyright (c) Microsoft Corporation.
2331
- const logger$c = credentialLogger("ManagedIdentityCredential - ArcMSI");
2420
+ const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
2421
+ const logger$c = credentialLogger(msiName$3);
2332
2422
  // Azure Arc MSI doesn't have a special expiresIn parser.
2333
2423
  const expiresInParser$3 = undefined;
2334
- function prepareRequestOptions$3(resource) {
2424
+ function prepareRequestOptions$3(scopes) {
2425
+ const resource = mapScopesToResource(scopes);
2426
+ if (!resource) {
2427
+ throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
2428
+ }
2335
2429
  const queryParameters = {
2336
2430
  resource,
2337
2431
  "api-version": azureArcAPIVersion
@@ -2339,7 +2433,7 @@ function prepareRequestOptions$3(resource) {
2339
2433
  const query = new URLSearchParams(queryParameters);
2340
2434
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2341
2435
  if (!process.env.IDENTITY_ENDPOINT) {
2342
- throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
2436
+ throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
2343
2437
  }
2344
2438
  return coreRestPipeline.createPipelineRequest({
2345
2439
  // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
@@ -2352,7 +2446,7 @@ function prepareRequestOptions$3(resource) {
2352
2446
  });
2353
2447
  }
2354
2448
  // Since "fs"'s readFileSync locks the thread, and to avoid extra dependencies.
2355
- function readFileAsync(path, options) {
2449
+ function readFileAsync$1(path, options) {
2356
2450
  return new Promise((resolve, reject) => fs.readFile(path, options, (err, data) => {
2357
2451
  if (err) {
2358
2452
  reject(err);
@@ -2367,7 +2461,7 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
2367
2461
  if (response.bodyAsText) {
2368
2462
  message = ` Response: ${response.bodyAsText}`;
2369
2463
  }
2370
- throw new AuthenticationError(response.status, `To authenticate with Azure Arc MSI, status code 401 is expected on the first request.${message}`);
2464
+ throw new AuthenticationError(response.status, `${msiName$3}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
2371
2465
  }
2372
2466
  const authHeader = response.headers.get("www-authenticate") || "";
2373
2467
  try {
@@ -2378,32 +2472,190 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
2378
2472
  }
2379
2473
  }
2380
2474
  const arcMsi = {
2381
- async isAvailable() {
2475
+ async isAvailable(scopes) {
2476
+ const resource = mapScopesToResource(scopes);
2477
+ if (!resource) {
2478
+ logger$c.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
2479
+ return false;
2480
+ }
2382
2481
  const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
2383
2482
  if (!result) {
2384
- logger$c.info("The Azure Arc MSI is unavailable.");
2483
+ logger$c.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
2385
2484
  }
2386
2485
  return result;
2387
2486
  },
2388
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2487
+ async getToken(configuration, getTokenOptions = {}) {
2389
2488
  var _a;
2390
- logger$c.info(`Using the Azure Arc MSI to authenticate.`);
2489
+ const { identityClient, scopes, clientId } = configuration;
2490
+ logger$c.info(`${msiName$3}: Authenticating.`);
2391
2491
  if (clientId) {
2392
- throw new Error("User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.");
2492
+ throw new Error(`${msiName$3}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`);
2393
2493
  }
2394
- const requestOptions = Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal, spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions }, prepareRequestOptions$3(resource));
2494
+ const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes)), { allowInsecureConnection: true });
2395
2495
  const filePath = await filePathRequest(identityClient, requestOptions);
2396
2496
  if (!filePath) {
2397
- throw new Error("Azure Arc MSI failed to find the token file.");
2497
+ throw new Error(`${msiName$3}: Failed to find the token file.`);
2398
2498
  }
2399
- const key = await readFileAsync(filePath, { encoding: "utf-8" });
2499
+ const key = await readFileAsync$1(filePath, { encoding: "utf-8" });
2400
2500
  (_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
2401
2501
  return msiGenericGetToken(identityClient, requestOptions, expiresInParser$3, getTokenOptions);
2402
2502
  }
2403
2503
  };
2404
2504
 
2405
2505
  // Copyright (c) Microsoft Corporation.
2406
- const logger$d = credentialLogger("ManagedIdentityCredential");
2506
+ const msiName$4 = "ManagedIdentityCredential - Token Exchange";
2507
+ const logger$d = credentialLogger(msiName$4);
2508
+ const readFileAsync$2 = util.promisify(fs__default.readFile);
2509
+ function expiresInParser$4(requestBody) {
2510
+ // Parses a string representation of the seconds since epoch into a number value
2511
+ return Number(requestBody.expires_on);
2512
+ }
2513
+ function prepareRequestOptions$4(scopes, clientAssertion, clientId) {
2514
+ var _a;
2515
+ const bodyParams = {
2516
+ scope: Array.isArray(scopes) ? scopes.join(" ") : scopes,
2517
+ client_assertion: clientAssertion,
2518
+ client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
2519
+ client_id: clientId,
2520
+ grant_type: "client_credentials"
2521
+ };
2522
+ const urlParams = new URLSearchParams(bodyParams);
2523
+ const url = new URL(`${process.env.AZURE_TENANT_ID}/oauth2/v2.0/token`, (_a = process.env.AZURE_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : DefaultAuthorityHost);
2524
+ return {
2525
+ url: url.toString(),
2526
+ method: "POST",
2527
+ body: urlParams.toString(),
2528
+ headers: coreRestPipeline.createHttpHeaders({
2529
+ Accept: "application/json"
2530
+ })
2531
+ };
2532
+ }
2533
+ function tokenExchangeMsi() {
2534
+ const azureFederatedTokenFilePath = process.env.AZURE_FEDERATED_TOKEN_FILE;
2535
+ let azureFederatedTokenFileContent = undefined;
2536
+ let cacheDate = undefined;
2537
+ // Only reads from the assertion file once every 5 minutes
2538
+ async function readAssertion() {
2539
+ // Cached assertions expire after 5 minutes
2540
+ if (cacheDate !== undefined && Date.now() - cacheDate >= 1000 * 60 * 5) {
2541
+ azureFederatedTokenFileContent = undefined;
2542
+ }
2543
+ if (!azureFederatedTokenFileContent) {
2544
+ const file = await readFileAsync$2(azureFederatedTokenFilePath, "utf8");
2545
+ const value = file.trim();
2546
+ if (!value) {
2547
+ throw new Error(`No content on the file ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`);
2548
+ }
2549
+ else {
2550
+ azureFederatedTokenFileContent = value;
2551
+ cacheDate = Date.now();
2552
+ }
2553
+ }
2554
+ return azureFederatedTokenFileContent;
2555
+ }
2556
+ return {
2557
+ async isAvailable(_scopes, _identityClient, clientId) {
2558
+ const env = process.env;
2559
+ const result = Boolean((clientId || env.AZURE_CLIENT_ID) && env.AZURE_TENANT_ID && azureFederatedTokenFilePath);
2560
+ if (!result) {
2561
+ logger$d.info(`${msiName$4}: 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`);
2562
+ }
2563
+ return result;
2564
+ },
2565
+ async getToken(configuration, getTokenOptions = {}) {
2566
+ const { identityClient, scopes, clientId } = configuration;
2567
+ logger$d.info(`${msiName$4}: Using the client assertion coming from environment variables.`);
2568
+ let assertion;
2569
+ try {
2570
+ assertion = await readAssertion();
2571
+ }
2572
+ catch (err) {
2573
+ throw new Error(`${msiName$4}: Failed to read ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`);
2574
+ }
2575
+ return msiGenericGetToken(identityClient, prepareRequestOptions$4(scopes, assertion, clientId || process.env.AZURE_CLIENT_ID), expiresInParser$4, getTokenOptions);
2576
+ }
2577
+ };
2578
+ }
2579
+
2580
+ // Copyright (c) Microsoft Corporation.
2581
+ const msiName$5 = "ManagedIdentityCredential - Fabric MSI";
2582
+ const logger$e = credentialLogger(msiName$5);
2583
+ function expiresInParser$5(requestBody) {
2584
+ // Parses a string representation of the seconds since epoch into a number value
2585
+ return Number(requestBody.expires_on);
2586
+ }
2587
+ function prepareRequestOptions$5(scopes, clientId) {
2588
+ const resource = mapScopesToResource(scopes);
2589
+ if (!resource) {
2590
+ throw new Error(`${msiName$5}: Multiple scopes are not supported.`);
2591
+ }
2592
+ const queryParameters = {
2593
+ resource,
2594
+ "api-version": azureFabricVersion
2595
+ };
2596
+ if (clientId) {
2597
+ queryParameters.client_id = clientId;
2598
+ }
2599
+ const query = new URLSearchParams(queryParameters);
2600
+ // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2601
+ if (!process.env.IDENTITY_ENDPOINT) {
2602
+ throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
2603
+ }
2604
+ if (!process.env.IDENTITY_HEADER) {
2605
+ throw new Error("Missing environment variable: IDENTITY_HEADER");
2606
+ }
2607
+ return {
2608
+ url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
2609
+ method: "GET",
2610
+ headers: coreRestPipeline.createHttpHeaders({
2611
+ Accept: "application/json",
2612
+ Secret: process.env.IDENTITY_HEADER
2613
+ })
2614
+ };
2615
+ }
2616
+ // This credential can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:
2617
+ //
2618
+ // FROM node:12
2619
+ // RUN wget https://host.any/path/bash.sh
2620
+ // CMD ["bash", "bash.sh"]
2621
+ //
2622
+ // Where the bash script contains:
2623
+ //
2624
+ // curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
2625
+ //
2626
+ const fabricMsi = {
2627
+ async isAvailable(scopes) {
2628
+ const resource = mapScopesToResource(scopes);
2629
+ if (!resource) {
2630
+ logger$e.info(`${msiName$5}: Unavailable. Multiple scopes are not supported.`);
2631
+ return false;
2632
+ }
2633
+ const env = process.env;
2634
+ const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT);
2635
+ if (!result) {
2636
+ logger$e.info(`${msiName$5}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`);
2637
+ }
2638
+ return result;
2639
+ },
2640
+ async getToken(configuration, getTokenOptions = {}) {
2641
+ const { scopes, identityClient, clientId } = configuration;
2642
+ logger$e.info([
2643
+ `${msiName$5}:`,
2644
+ "Using the endpoint and the secret coming from the environment variables:",
2645
+ `IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,
2646
+ "IDENTITY_HEADER=[REDACTED] and",
2647
+ "IDENTITY_SERVER_THUMBPRINT=[REDACTED]."
2648
+ ].join(" "));
2649
+ return msiGenericGetToken(identityClient, prepareRequestOptions$5(scopes, clientId), expiresInParser$5, getTokenOptions, new https.Agent({
2650
+ // This is necessary because Service Fabric provides a self-signed certificate.
2651
+ // The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable.
2652
+ rejectUnauthorized: false
2653
+ }));
2654
+ }
2655
+ };
2656
+
2657
+ // Copyright (c) Microsoft Corporation.
2658
+ const logger$f = credentialLogger("ManagedIdentityCredential");
2407
2659
  /**
2408
2660
  * Attempts authentication using a managed identity that has been assigned
2409
2661
  * to the deployment environment. This authentication type works in Azure VMs,
@@ -2430,15 +2682,13 @@ class ManagedIdentityCredential {
2430
2682
  this.identityClient = new IdentityClient(clientIdOrOptions);
2431
2683
  }
2432
2684
  }
2433
- async cachedAvailableMSI(resource, clientId, getTokenOptions) {
2685
+ async cachedAvailableMSI(scopes, clientId, getTokenOptions) {
2434
2686
  if (this.cachedMSI) {
2435
2687
  return this.cachedMSI;
2436
2688
  }
2437
- // "fabricMsi" can't be added yet because our HTTPs pipeline doesn't allow skipping the SSL verification step,
2438
- // which is necessary since Service Fabric only provides self-signed certificates on their Identity Endpoint.
2439
- const MSIs = [appServiceMsi2017, cloudShellMsi, arcMsi, imdsMsi];
2689
+ const MSIs = [fabricMsi, appServiceMsi2017, cloudShellMsi, arcMsi, tokenExchangeMsi(), imdsMsi];
2440
2690
  for (const msi of MSIs) {
2441
- if (await msi.isAvailable(this.identityClient, resource, clientId, getTokenOptions)) {
2691
+ if (await msi.isAvailable(scopes, this.identityClient, clientId, getTokenOptions)) {
2442
2692
  this.cachedMSI = msi;
2443
2693
  return msi;
2444
2694
  }
@@ -2446,12 +2696,15 @@ class ManagedIdentityCredential {
2446
2696
  throw new CredentialUnavailableError("ManagedIdentityCredential - No MSI credential available");
2447
2697
  }
2448
2698
  async authenticateManagedIdentity(scopes, clientId, getTokenOptions) {
2449
- const resource = mapScopesToResource(scopes);
2450
2699
  const { span, updatedOptions } = createSpan("ManagedIdentityCredential-authenticateManagedIdentity", getTokenOptions);
2451
2700
  try {
2452
2701
  // Determining the available MSI, and avoiding checking for other MSIs while the program is running.
2453
- const availableMSI = await this.cachedAvailableMSI(resource, clientId, updatedOptions);
2454
- return availableMSI.getToken(this.identityClient, resource, clientId, updatedOptions);
2702
+ const availableMSI = await this.cachedAvailableMSI(scopes, clientId, updatedOptions);
2703
+ return availableMSI.getToken({
2704
+ identityClient: this.identityClient,
2705
+ scopes,
2706
+ clientId
2707
+ }, updatedOptions);
2455
2708
  }
2456
2709
  catch (err) {
2457
2710
  span.setStatus({
@@ -2475,7 +2728,7 @@ class ManagedIdentityCredential {
2475
2728
  */
2476
2729
  async getToken(scopes, options) {
2477
2730
  let result = null;
2478
- const { span, updatedOptions } = createSpan("ManagedIdentityCredential-getToken", options);
2731
+ const { span, updatedOptions } = createSpan("ManagedIdentityCredential.getToken", options);
2479
2732
  try {
2480
2733
  // isEndpointAvailable can be true, false, or null,
2481
2734
  // If it's null, it means we don't yet know whether
@@ -2490,7 +2743,7 @@ class ManagedIdentityCredential {
2490
2743
  // It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
2491
2744
  // yet we had no access token. For this reason, we'll throw once with a specific message:
2492
2745
  const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2493
- logger$d.getToken.info(formatError(scopes, error));
2746
+ logger$f.getToken.info(formatError(scopes, error));
2494
2747
  throw error;
2495
2748
  }
2496
2749
  // Since `authenticateManagedIdentity` didn't throw, and the result was not null,
@@ -2502,10 +2755,10 @@ class ManagedIdentityCredential {
2502
2755
  // We've previously determined that the endpoint was unavailable,
2503
2756
  // either because it was unreachable or permanently unable to authenticate.
2504
2757
  const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
2505
- logger$d.getToken.info(formatError(scopes, error));
2758
+ logger$f.getToken.info(formatError(scopes, error));
2506
2759
  throw error;
2507
2760
  }
2508
- logger$d.getToken.info(formatSuccess(scopes));
2761
+ logger$f.getToken.info(formatSuccess(scopes));
2509
2762
  return result;
2510
2763
  }
2511
2764
  catch (err) {
@@ -2526,21 +2779,21 @@ class ManagedIdentityCredential {
2526
2779
  // If either the network is unreachable,
2527
2780
  // we can safely assume the credential is unavailable.
2528
2781
  if (err.code === "ENETUNREACH") {
2529
- const error = new CredentialUnavailableError("ManagedIdentityCredential is unavailable. Network unreachable.");
2530
- logger$d.getToken.info(formatError(scopes, error));
2782
+ const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. Network unreachable. Message: ${err.message}`);
2783
+ logger$f.getToken.info(formatError(scopes, error));
2531
2784
  throw error;
2532
2785
  }
2533
2786
  // If either the host was unreachable,
2534
2787
  // we can safely assume the credential is unavailable.
2535
2788
  if (err.code === "EHOSTUNREACH") {
2536
- const error = new CredentialUnavailableError("ManagedIdentityCredential is unavailable. No managed identity endpoint found.");
2537
- logger$d.getToken.info(formatError(scopes, error));
2789
+ const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. No managed identity endpoint found. Message: ${err.message}`);
2790
+ logger$f.getToken.info(formatError(scopes, error));
2538
2791
  throw error;
2539
2792
  }
2540
2793
  // If err.statusCode has a value of 400, it comes from sendTokenRequest,
2541
2794
  // and it means that the endpoint is working, but that no identity is available.
2542
2795
  if (err.statusCode === 400) {
2543
- throw new CredentialUnavailableError("The managed identity endpoint is indicating there's no available identity");
2796
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
2544
2797
  }
2545
2798
  // If the error has no status code, we can assume there was no available identity.
2546
2799
  // This will throw silently during any ChainedTokenCredential.
@@ -2588,36 +2841,37 @@ const defaultCredentials = [
2588
2841
  ];
2589
2842
  /**
2590
2843
  * Provides a default {@link ChainedTokenCredential} configuration that should
2591
- * work for most applications that use the Azure SDK. The following credential
2592
- * types will be tried, in order:
2593
- *
2594
- * - {@link EnvironmentCredential}
2595
- * - {@link ManagedIdentityCredential}
2596
- * - {@link VisualStudioCodeCredential}
2597
- * - {@link AzureCliCredential}
2598
- * - {@link AzurePowerShellCredential}
2599
- *
2600
- * Consult the documentation of these credential types for more information
2601
- * on how they attempt authentication.
2602
- *
2603
- * **Note**: `VisualStudioCodeCredential` is provided by an extension package:
2604
- * `@azure/identity-vscode`. If this package is not installed and registered
2605
- * using the extension API (`useIdentityExtension`), then authentication using
2606
- * `VisualStudioCodeCredential` will not be available.
2607
- *
2608
- * Azure Identity extensions may add credential types to the default credential
2609
- * stack.
2844
+ * work for most applications that use the Azure SDK.
2610
2845
  */
2611
2846
  class DefaultAzureCredential extends ChainedTokenCredential {
2612
2847
  /**
2613
2848
  * Creates an instance of the DefaultAzureCredential class.
2614
2849
  *
2850
+ * This credential provides a default {@link ChainedTokenCredential} configuration that should
2851
+ * work for most applications that use the Azure SDK.
2852
+ *
2853
+ * The following credential types will be tried, in order:
2854
+ *
2855
+ * - {@link EnvironmentCredential}
2856
+ * - {@link ManagedIdentityCredential}
2857
+ * - {@link VisualStudioCodeCredential}
2858
+ * - {@link AzureCliCredential}
2859
+ * - {@link AzurePowerShellCredential}
2860
+ *
2861
+ * Consult the documentation of these credential types for more information
2862
+ * on how they attempt authentication.
2863
+ *
2864
+ * **Note**: `VisualStudioCodeCredential` is provided by a plugin package:
2865
+ * `@azure/identity-vscode`. If this package is not installed and registered
2866
+ * using the plugin API (`useIdentityPlugin`), then authentication using
2867
+ * `VisualStudioCodeCredential` will not be available.
2868
+ *
2615
2869
  * @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.
2616
2870
  */
2617
2871
  constructor(options) {
2618
2872
  super(...defaultCredentials.map((ctor) => new ctor(options)));
2619
2873
  this.UnavailableMessage =
2620
- "DefaultAzureCredential => failed to retrieve a token from the included credentials";
2874
+ "DefaultAzureCredential => failed to retrieve a token from the included credentials. To troubleshoot, visit https://aka.ms/azsdk/js/identity/defaultazurecredential/troubleshoot.";
2621
2875
  }
2622
2876
  }
2623
2877
 
@@ -2765,29 +3019,29 @@ class MsalOpenBrowser extends MsalNode {
2765
3019
  }
2766
3020
 
2767
3021
  // Copyright (c) Microsoft Corporation.
2768
- const logger$e = credentialLogger("InteractiveBrowserCredential");
3022
+ const logger$g = credentialLogger("InteractiveBrowserCredential");
2769
3023
  /**
2770
3024
  * Enables authentication to Azure Active Directory inside of the web browser
2771
3025
  * using the interactive login flow.
2772
- *
2773
- * This credential uses the [Authorization Code Flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow).
2774
- * On Node.js, it will open a browser window while it listens for a redirect response from the authentication service.
2775
- * On browsers, it authenticates via popups. The `loginStyle` optional parameter can be set to `redirect` to authenticate by redirecting the user to an Azure secure login page, which then will redirect the user back to the web application where the authentication started.
2776
- *
2777
- * For Node.js, if a `clientId` is provided, the Azure Active Directory application will need to be configured to have a "Mobile and desktop applications" redirect endpoint.
2778
- * Follow our guide on [setting up Redirect URIs for Desktop apps that calls to web APIs](https://docs.microsoft.com/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris).
2779
3026
  */
2780
3027
  class InteractiveBrowserCredential {
2781
3028
  /**
2782
3029
  * Creates an instance of InteractiveBrowserCredential with the details needed.
2783
3030
  *
3031
+ * This credential uses the [Authorization Code Flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow).
3032
+ * On Node.js, it will open a browser window while it listens for a redirect response from the authentication service.
3033
+ * On browsers, it authenticates via popups. The `loginStyle` optional parameter can be set to `redirect` to authenticate by redirecting the user to an Azure secure login page, which then will redirect the user back to the web application where the authentication started.
3034
+ *
3035
+ * For Node.js, if a `clientId` is provided, the Azure Active Directory application will need to be configured to have a "Mobile and desktop applications" redirect endpoint.
3036
+ * Follow our guide on [setting up Redirect URIs for Desktop apps that calls to web APIs](https://docs.microsoft.com/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris).
3037
+ *
2784
3038
  * @param options - Options for configuring the client which makes the authentication requests.
2785
3039
  */
2786
3040
  constructor(options = {}) {
2787
3041
  const redirectUri = typeof options.redirectUri === "function"
2788
3042
  ? options.redirectUri()
2789
3043
  : options.redirectUri || "http://localhost";
2790
- this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$e,
3044
+ this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$g,
2791
3045
  redirectUri }));
2792
3046
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
2793
3047
  }
@@ -2865,7 +3119,7 @@ class MsalDeviceCode extends MsalNode {
2865
3119
  }
2866
3120
 
2867
3121
  // Copyright (c) Microsoft Corporation.
2868
- const logger$f = credentialLogger("DeviceCodeCredential");
3122
+ const logger$h = credentialLogger("DeviceCodeCredential");
2869
3123
  /**
2870
3124
  * Method that logs the user code from the DeviceCodeCredential.
2871
3125
  * @param deviceCodeInfo - The device code.
@@ -2882,10 +3136,24 @@ class DeviceCodeCredential {
2882
3136
  * Creates an instance of DeviceCodeCredential with the details needed
2883
3137
  * to initiate the device code authorization flow with Azure Active Directory.
2884
3138
  *
3139
+ * A message will be logged, giving users a code that they can use to authenticate once they go to https://microsoft.com/devicelogin
3140
+ *
3141
+ * Developers can configure how this message is shown by passing a custom `userPromptCallback`:
3142
+ *
3143
+ * ```js
3144
+ * const credential = new DeviceCodeCredential({
3145
+ * tenantId: env.AZURE_TENANT_ID,
3146
+ * clientId: env.AZURE_CLIENT_ID,
3147
+ * userPromptCallback: (info) => {
3148
+ * console.log("CUSTOMIZED PROMPT CALLBACK", info.message);
3149
+ * }
3150
+ * });
3151
+ * ```
3152
+ *
2885
3153
  * @param options - Options for configuring the client which makes the authentication requests.
2886
3154
  */
2887
3155
  constructor(options) {
2888
- this.msalFlow = new MsalDeviceCode(Object.assign(Object.assign({}, options), { logger: logger$f, userPromptCallback: (options === null || options === void 0 ? void 0 : options.userPromptCallback) || defaultDeviceCodePromptCallback, tokenCredentialOptions: options || {} }));
3156
+ this.msalFlow = new MsalDeviceCode(Object.assign(Object.assign({}, options), { logger: logger$h, userPromptCallback: (options === null || options === void 0 ? void 0 : options.userPromptCallback) || defaultDeviceCodePromptCallback, tokenCredentialOptions: options || {} }));
2889
3157
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
2890
3158
  }
2891
3159
  /**
@@ -2926,7 +3194,45 @@ class DeviceCodeCredential {
2926
3194
  }
2927
3195
 
2928
3196
  // Copyright (c) Microsoft Corporation.
2929
- const logger$g = credentialLogger("AuthorizationCodeCredential");
3197
+ /**
3198
+ * This MSAL client sets up a web server to listen for redirect callbacks, then calls to the MSAL's public application's `acquireTokenByDeviceCode` during `doGetToken`
3199
+ * to trigger the authentication flow, and then respond based on the values obtained from the redirect callback
3200
+ * @internal
3201
+ */
3202
+ class MsalAuthorizationCode extends MsalNode {
3203
+ constructor(options) {
3204
+ super(options);
3205
+ this.logger = credentialLogger("Node.js MSAL Authorization Code");
3206
+ this.redirectUri = options.redirectUri;
3207
+ this.authorizationCode = options.authorizationCode;
3208
+ if (options.clientSecret) {
3209
+ this.msalConfig.auth.clientSecret = options.clientSecret;
3210
+ }
3211
+ }
3212
+ async getAuthCodeUrl(options) {
3213
+ await this.init();
3214
+ return this.confidentialApp.getAuthCodeUrl(options);
3215
+ }
3216
+ async doGetToken(scopes, options) {
3217
+ var _a;
3218
+ try {
3219
+ const result = await ((_a = this.confidentialApp) === null || _a === void 0 ? void 0 : _a.acquireTokenByCode({
3220
+ scopes,
3221
+ redirectUri: this.redirectUri,
3222
+ code: this.authorizationCode
3223
+ }));
3224
+ // The Client Credential flow does not return an account,
3225
+ // so each time getToken gets called, we will have to acquire a new token through the service.
3226
+ return this.handleResult(scopes, this.clientId, result || undefined);
3227
+ }
3228
+ catch (err) {
3229
+ throw this.handleError(scopes, err, options);
3230
+ }
3231
+ }
3232
+ }
3233
+
3234
+ // Copyright (c) Microsoft Corporation.
3235
+ const logger$i = credentialLogger("AuthorizationCodeCredential");
2930
3236
  /**
2931
3237
  * Enables authentication to Azure Active Directory using an authorization code
2932
3238
  * that was obtained through the authorization code flow, described in more detail
@@ -2940,26 +3246,23 @@ class AuthorizationCodeCredential {
2940
3246
  * @internal
2941
3247
  */
2942
3248
  constructor(tenantId, clientId, clientSecretOrAuthorizationCode, authorizationCodeOrRedirectUri, redirectUriOrOptions, options) {
2943
- this.lastTokenResponse = null;
2944
- checkTenantId(logger$g, tenantId);
2945
- this.clientId = clientId;
2946
- this.tenantId = tenantId;
3249
+ checkTenantId(logger$i, tenantId);
3250
+ let clientSecret = clientSecretOrAuthorizationCode;
2947
3251
  if (typeof redirectUriOrOptions === "string") {
2948
3252
  // the clientId+clientSecret constructor
2949
- this.clientSecret = clientSecretOrAuthorizationCode;
2950
3253
  this.authorizationCode = authorizationCodeOrRedirectUri;
2951
3254
  this.redirectUri = redirectUriOrOptions;
2952
3255
  // options okay
2953
3256
  }
2954
3257
  else {
2955
3258
  // clientId only
2956
- this.clientSecret = undefined;
2957
3259
  this.authorizationCode = clientSecretOrAuthorizationCode;
2958
3260
  this.redirectUri = authorizationCodeOrRedirectUri;
3261
+ clientSecret = undefined;
2959
3262
  options = redirectUriOrOptions;
2960
3263
  }
2961
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
2962
- this.identityClient = new IdentityClient(options);
3264
+ this.msalFlow = new MsalAuthorizationCode(Object.assign(Object.assign({}, options), { clientSecret,
3265
+ clientId, tokenCredentialOptions: options || {}, logger: logger$i, redirectUri: this.redirectUri, authorizationCode: this.authorizationCode }));
2963
3266
  }
2964
3267
  /**
2965
3268
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -2969,100 +3272,116 @@ class AuthorizationCodeCredential {
2969
3272
  * @param options - The options used to configure any requests this
2970
3273
  * TokenCredential implementation might make.
2971
3274
  */
2972
- async getToken(scopes, options) {
2973
- var _a, _b;
2974
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
2975
- this.tenantId;
2976
- const { span, updatedOptions } = createSpan("AuthorizationCodeCredential-getToken", options);
2977
- try {
2978
- let tokenResponse = null;
2979
- let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
2980
- if (scopeString.indexOf("offline_access") < 0) {
2981
- scopeString += " offline_access";
2982
- }
2983
- // Try to use the refresh token first
2984
- if (this.lastTokenResponse && this.lastTokenResponse.refreshToken) {
2985
- tokenResponse = await this.identityClient.refreshAccessToken(tenantId, this.clientId, scopeString, this.lastTokenResponse.refreshToken, this.clientSecret, undefined, updatedOptions);
2986
- }
2987
- const query = new URLSearchParams({
2988
- client_id: this.clientId,
2989
- grant_type: "authorization_code",
2990
- scope: scopeString,
2991
- code: this.authorizationCode,
2992
- redirect_uri: this.redirectUri
2993
- });
2994
- if (this.clientSecret) {
2995
- query.set("client_secret", this.clientSecret);
2996
- }
2997
- if (tokenResponse === null) {
2998
- const urlSuffix = getIdentityTokenEndpointSuffix(tenantId);
2999
- const pipelineRequest = coreRestPipeline.createPipelineRequest({
3000
- url: `${this.identityClient.authorityHost}/${tenantId}/${urlSuffix}`,
3001
- method: "POST",
3002
- body: query.toString(),
3003
- headers: coreRestPipeline.createHttpHeaders({
3004
- Accept: "application/json",
3005
- "Content-Type": "application/x-www-form-urlencoded"
3006
- }),
3007
- tracingOptions: {
3008
- spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
3009
- tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
3010
- }
3011
- });
3012
- tokenResponse = await this.identityClient.sendTokenRequest(pipelineRequest, (response) => new Date(response === null || response === void 0 ? void 0 : response.expires_on).getTime());
3275
+ async getToken(scopes, options = {}) {
3276
+ return trace(`${this.constructor.name}.getToken`, options, async (newOptions) => {
3277
+ const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
3278
+ return this.msalFlow.getToken(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication }));
3279
+ });
3280
+ }
3281
+ }
3282
+
3283
+ // Copyright (c) Microsoft Corporation.
3284
+ /**
3285
+ * MSAL on behalf of flow. Calls to MSAL's confidential application's `acquireTokenOnBehalfOf` during `doGetToken`.
3286
+ * @internal
3287
+ */
3288
+ class MsalOnBehalfOf extends MsalNode {
3289
+ constructor(options) {
3290
+ super(options);
3291
+ this.logger.info("Initialized MSAL's On-Behalf-Of flow");
3292
+ this.requiresConfidential = true;
3293
+ this.userAssertionToken = options.userAssertionToken;
3294
+ this.certificatePath = options.certificatePath;
3295
+ this.sendCertificateChain = options.sendCertificateChain;
3296
+ this.clientSecret = options.clientSecret;
3297
+ }
3298
+ // Changing the MSAL configuration asynchronously
3299
+ async init(options) {
3300
+ if (this.certificatePath) {
3301
+ try {
3302
+ const parts = await parseCertificate({ certificatePath: this.certificatePath }, this.sendCertificateChain);
3303
+ this.msalConfig.auth.clientCertificate = {
3304
+ thumbprint: parts.thumbprint,
3305
+ privateKey: parts.certificateContents,
3306
+ x5c: parts.x5c
3307
+ };
3013
3308
  }
3014
- this.lastTokenResponse = tokenResponse;
3015
- logger$g.getToken.info(formatSuccess(scopes));
3016
- const token = tokenResponse && tokenResponse.accessToken;
3017
- if (!token) {
3018
- throw new CredentialUnavailableError("Failed to retrieve a valid token");
3309
+ catch (error) {
3310
+ this.logger.info(formatError("", error));
3311
+ throw error;
3019
3312
  }
3020
- return token;
3021
3313
  }
3022
- catch (err) {
3023
- span.setStatus({
3024
- code: coreTracing.SpanStatusCode.ERROR,
3025
- message: err.message
3314
+ else {
3315
+ this.msalConfig.auth.clientSecret = this.clientSecret;
3316
+ }
3317
+ return super.init(options);
3318
+ }
3319
+ async doGetToken(scopes, options = {}) {
3320
+ try {
3321
+ const result = await this.confidentialApp.acquireTokenOnBehalfOf({
3322
+ scopes,
3323
+ correlationId: options.correlationId,
3324
+ authority: options.authority,
3325
+ oboAssertion: this.userAssertionToken
3026
3326
  });
3027
- logger$g.getToken.info(formatError(scopes, err));
3028
- throw err;
3327
+ return this.handleResult(scopes, this.clientId, result || undefined);
3029
3328
  }
3030
- finally {
3031
- span.end();
3329
+ catch (err) {
3330
+ throw this.handleError(scopes, err, options);
3032
3331
  }
3033
3332
  }
3034
3333
  }
3035
3334
 
3036
3335
  // Copyright (c) Microsoft Corporation.
3037
- const ApplicationCredentials = [
3038
- EnvironmentCredential,
3039
- DefaultManagedIdentityCredential
3040
- ];
3336
+ const credentialName$1 = "OnBehalfOfCredential";
3337
+ const logger$j = credentialLogger(credentialName$1);
3041
3338
  /**
3042
- * Provides a default {@link ChainedTokenCredential} configuration that should
3043
- * work for most applications that use the Azure SDK. The following credential
3044
- * types will be tried, in order:
3045
- *
3046
- * - {@link EnvironmentCredential}
3047
- * - {@link ManagedIdentityCredential}
3048
-
3049
- *
3050
- * Consult the documentation of these credential types for more information
3051
- * on how they attempt authentication.
3052
- *
3053
- * Azure Identity extensions may add credential types to the default credential
3054
- * stack.
3339
+ * Enables authentication to Azure Active Directory using the [On Behalf Of flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow).
3055
3340
  */
3056
- class ApplicationCredential extends ChainedTokenCredential {
3341
+ class OnBehalfOfCredential {
3057
3342
  /**
3058
- * Creates an instance of the ApplicationCredential class.
3343
+ * Creates an instance of the {@link OnBehalfOfCredential} with the details
3344
+ * needed to authenticate against Azure Active Directory with a client
3345
+ * secret or a path to a PEM certificate, and an user assertion.
3346
+ *
3347
+ * Example using the `KeyClient` from [\@azure/keyvault-keys](https://www.npmjs.com/package/\@azure/keyvault-keys):
3348
+ *
3349
+ * ```ts
3350
+ * const tokenCredential = new OnBehalfOfCredential({
3351
+ * tenantId,
3352
+ * clientId,
3353
+ * clientSecret, // or `certificatePath: "/path/to/certificate.pem"
3354
+ * userAssertionToken: "access-token"
3355
+ * });
3356
+ * const client = new KeyClient("vault-url", tokenCredential);
3357
+ *
3358
+ * await client.getKey("key-name");
3359
+ * ```
3059
3360
  *
3060
- * @param options - Optional parameters. See {@link ApplicationCredentialOptions}.
3361
+ * @param options - Optional parameters, generally common across credentials.
3061
3362
  */
3062
3363
  constructor(options) {
3063
- super(...ApplicationCredentials.map((ctor) => new ctor(options)));
3064
- this.UnavailableMessage =
3065
- "ApplicationCredential => failed to retrieve a token from the included credentials";
3364
+ this.options = options;
3365
+ const { clientSecret } = options;
3366
+ const { certificatePath } = options;
3367
+ const { tenantId, clientId, userAssertionToken } = options;
3368
+ if (!tenantId || !clientId || !(clientSecret || certificatePath) || !userAssertionToken) {
3369
+ throw new Error(`${credentialName$1}: tenantId, clientId, clientSecret (or certificatePath) and userAssertionToken are required parameters.`);
3370
+ }
3371
+ this.msalFlow = new MsalOnBehalfOf(Object.assign(Object.assign({}, this.options), { logger: logger$j, tokenCredentialOptions: this.options }));
3372
+ }
3373
+ /**
3374
+ * Authenticates with Azure Active Directory and returns an access token if successful.
3375
+ * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
3376
+ *
3377
+ * @param scopes - The list of scopes for which the token will have access.
3378
+ * @param options - The options used to configure the underlying network requests.
3379
+ */
3380
+ async getToken(scopes, options = {}) {
3381
+ return trace(`${credentialName$1}.getToken`, options, async (newOptions) => {
3382
+ const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
3383
+ return this.msalFlow.getToken(arrayScopes, newOptions);
3384
+ });
3066
3385
  }
3067
3386
  }
3068
3387
 
@@ -3076,7 +3395,6 @@ function getDefaultAzureCredential() {
3076
3395
 
3077
3396
  exports.AggregateAuthenticationError = AggregateAuthenticationError;
3078
3397
  exports.AggregateAuthenticationErrorName = AggregateAuthenticationErrorName;
3079
- exports.ApplicationCredential = ApplicationCredential;
3080
3398
  exports.AuthenticationError = AuthenticationError;
3081
3399
  exports.AuthenticationErrorName = AuthenticationErrorName;
3082
3400
  exports.AuthenticationRequiredError = AuthenticationRequiredError;
@@ -3093,11 +3411,12 @@ exports.DeviceCodeCredential = DeviceCodeCredential;
3093
3411
  exports.EnvironmentCredential = EnvironmentCredential;
3094
3412
  exports.InteractiveBrowserCredential = InteractiveBrowserCredential;
3095
3413
  exports.ManagedIdentityCredential = ManagedIdentityCredential;
3414
+ exports.OnBehalfOfCredential = OnBehalfOfCredential;
3096
3415
  exports.UsernamePasswordCredential = UsernamePasswordCredential;
3097
3416
  exports.VisualStudioCodeCredential = VisualStudioCodeCredential;
3098
3417
  exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
3099
3418
  exports.getDefaultAzureCredential = getDefaultAzureCredential;
3100
3419
  exports.logger = logger;
3101
3420
  exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
3102
- exports.useIdentityExtension = useIdentityExtension;
3421
+ exports.useIdentityPlugin = useIdentityPlugin;
3103
3422
  //# sourceMappingURL=index.js.map