@azure/identity 2.0.0-beta.4 → 2.0.1-alpha.20211025.3

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 (132) hide show
  1. package/CHANGELOG.md +215 -4
  2. package/README.md +78 -25
  3. package/dist/index.js +888 -477
  4. package/dist/index.js.map +1 -1
  5. package/dist-esm/src/client/identityClient.js +75 -62
  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 -74
  10. package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
  11. package/dist-esm/src/credentials/azureApplicationCredential.browser.js +34 -0
  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 +3 -3
  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 +17 -19
  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.browser.js +1 -1
  37. package/dist-esm/src/credentials/defaultAzureCredential.browser.js.map +1 -1
  38. package/dist-esm/src/credentials/defaultAzureCredential.js +22 -21
  39. package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
  40. package/dist-esm/src/credentials/deviceCodeCredential.browser.js +7 -0
  41. package/dist-esm/src/credentials/deviceCodeCredential.browser.js.map +1 -1
  42. package/dist-esm/src/credentials/deviceCodeCredential.js +14 -0
  43. package/dist-esm/src/credentials/deviceCodeCredential.js.map +1 -1
  44. package/dist-esm/src/credentials/deviceCodeCredentialOptions.js.map +1 -1
  45. package/dist-esm/src/credentials/environmentCredential.browser.js +7 -0
  46. package/dist-esm/src/credentials/environmentCredential.browser.js.map +1 -1
  47. package/dist-esm/src/credentials/environmentCredential.js +5 -21
  48. package/dist-esm/src/credentials/environmentCredential.js.map +1 -1
  49. package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js +7 -7
  50. package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js.map +1 -1
  51. package/dist-esm/src/credentials/interactiveBrowserCredential.js +7 -7
  52. package/dist-esm/src/credentials/interactiveBrowserCredential.js.map +1 -1
  53. package/dist-esm/src/credentials/interactiveBrowserCredentialOptions.js.map +1 -1
  54. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +31 -12
  55. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
  56. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +45 -23
  57. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
  58. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +29 -13
  59. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
  60. package/dist-esm/src/credentials/managedIdentityCredential/constants.js +2 -1
  61. package/dist-esm/src/credentials/managedIdentityCredential/constants.js.map +1 -1
  62. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +36 -11
  63. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
  64. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +69 -47
  65. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
  66. package/dist-esm/src/credentials/managedIdentityCredential/index.js +19 -17
  67. package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
  68. package/dist-esm/src/credentials/managedIdentityCredential/models.js.map +1 -1
  69. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +82 -0
  70. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -0
  71. package/dist-esm/src/credentials/managedIdentityCredential/utils.js +16 -4
  72. package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
  73. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js +23 -0
  74. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js.map +1 -0
  75. package/dist-esm/src/credentials/onBehalfOfCredential.js +57 -0
  76. package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -0
  77. package/dist-esm/src/credentials/{visualStudioCodeCredentialExtension.js → onBehalfOfCredentialOptions.js} +1 -1
  78. package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -0
  79. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js +17 -19
  80. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
  81. package/dist-esm/src/credentials/usernamePasswordCredential.js +3 -2
  82. package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
  83. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js +7 -1
  84. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js.map +1 -1
  85. package/dist-esm/src/credentials/visualStudioCodeCredential.js +16 -8
  86. package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
  87. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js +4 -0
  88. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js.map +1 -0
  89. package/dist-esm/src/{client/errors.js → errors.js} +16 -1
  90. package/dist-esm/src/errors.js.map +1 -0
  91. package/dist-esm/src/index.js +3 -4
  92. package/dist-esm/src/index.js.map +1 -1
  93. package/dist-esm/src/msal/browserFlows/browserCommon.js +8 -7
  94. package/dist-esm/src/msal/browserFlows/browserCommon.js.map +1 -1
  95. package/dist-esm/src/msal/browserFlows/msalAuthCode.js +12 -4
  96. package/dist-esm/src/msal/browserFlows/msalAuthCode.js.map +1 -1
  97. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +41 -0
  98. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -0
  99. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +49 -29
  100. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
  101. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
  102. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +56 -0
  103. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -0
  104. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +2 -2
  105. package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +1 -1
  106. package/dist-esm/src/msal/nodeFlows/nodeCommon.js +32 -13
  107. package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +1 -1
  108. package/dist-esm/src/msal/nodeFlows/tokenCachePersistenceOptions.js.map +1 -1
  109. package/dist-esm/src/msal/utils.js +15 -8
  110. package/dist-esm/src/msal/utils.js.map +1 -1
  111. package/dist-esm/src/plugins/consumer.browser.js +7 -0
  112. package/dist-esm/src/plugins/consumer.browser.js.map +1 -0
  113. package/dist-esm/src/{extensions → plugins}/consumer.js +12 -12
  114. package/dist-esm/src/plugins/consumer.js.map +1 -0
  115. package/dist-esm/src/{extensions → plugins}/provider.js +0 -0
  116. package/dist-esm/src/plugins/provider.js.map +1 -0
  117. package/dist-esm/src/util/tracing.js +2 -2
  118. package/dist-esm/src/util/tracing.js.map +1 -1
  119. package/dist-esm/src/util/validateMultiTenant.browser.js +22 -0
  120. package/dist-esm/src/util/validateMultiTenant.browser.js.map +1 -0
  121. package/dist-esm/src/util/validateMultiTenant.js +17 -12
  122. package/dist-esm/src/util/validateMultiTenant.js.map +1 -1
  123. package/package.json +38 -21
  124. package/types/identity.d.ts +250 -225
  125. package/dist-esm/src/client/errors.js.map +0 -1
  126. package/dist-esm/src/credentials/visualStudioCodeCredentialExtension.js.map +0 -1
  127. package/dist-esm/src/extensions/consumer.browser.js +0 -7
  128. package/dist-esm/src/extensions/consumer.browser.js.map +0 -1
  129. package/dist-esm/src/extensions/consumer.js.map +0 -1
  130. package/dist-esm/src/extensions/provider.js.map +0 -1
  131. package/dist-esm/src/msal/errors.js +0 -22
  132. package/dist-esm/src/msal/errors.js.map +0 -1
package/dist/index.js CHANGED
@@ -5,11 +5,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
6
 
7
7
  var msalNode = require('@azure/msal-node');
8
- var qs = _interopDefault(require('qs'));
9
- var coreHttp = require('@azure/core-http');
8
+ var coreClient = require('@azure/core-client');
10
9
  var coreTracing = require('@azure/core-tracing');
10
+ var coreUtil = require('@azure/core-util');
11
+ var coreRestPipeline = require('@azure/core-rest-pipeline');
11
12
  var abortController = require('@azure/abort-controller');
12
- var logger$h = require('@azure/logger');
13
+ var logger$k = require('@azure/logger');
13
14
  var msalCommon = require('@azure/msal-common');
14
15
  var uuid = require('uuid');
15
16
  var fs = require('fs');
@@ -17,7 +18,10 @@ var fs__default = _interopDefault(fs);
17
18
  var os = _interopDefault(require('os'));
18
19
  var path = _interopDefault(require('path'));
19
20
  var child_process = require('child_process');
21
+ var child_process__default = _interopDefault(child_process);
20
22
  var crypto = require('crypto');
23
+ var util = require('util');
24
+ var https = _interopDefault(require('https'));
21
25
  var http = _interopDefault(require('http'));
22
26
  var open = _interopDefault(require('open'));
23
27
  var stoppable = _interopDefault(require('stoppable'));
@@ -147,7 +151,7 @@ const AggregateAuthenticationErrorName = "AggregateAuthenticationError";
147
151
  class AggregateAuthenticationError extends Error {
148
152
  constructor(errors, errorMessage) {
149
153
  const errorDetail = errors.join("\n");
150
- super(`${errorMessage}\n\n${errorDetail}`);
154
+ super(`${errorMessage}\n${errorDetail}`);
151
155
  this.errors = errors;
152
156
  // Ensure that this type reports the correct name
153
157
  this.name = AggregateAuthenticationErrorName;
@@ -163,6 +167,21 @@ function convertOAuthErrorResponseToErrorResponse(errorBody) {
163
167
  traceId: errorBody.trace_id
164
168
  };
165
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
+ }
166
185
 
167
186
  // Copyright (c) Microsoft Corporation.
168
187
  // Licensed under the MIT license.
@@ -181,7 +200,7 @@ function getIdentityTokenEndpointSuffix(tenantId) {
181
200
  * @internal
182
201
  */
183
202
  const createSpan = coreTracing.createSpanFunction({
184
- packagePrefix: "Azure.Identity",
203
+ packagePrefix: "",
185
204
  namespace: "Microsoft.AAD"
186
205
  });
187
206
  /**
@@ -189,7 +208,7 @@ const createSpan = coreTracing.createSpanFunction({
189
208
  * Traces an operation and properly handles reporting start, end and errors for a given span
190
209
  *
191
210
  * @param operationName - Name of a method in the TClient type
192
- * @param options - An options class, typically derived from \@azure/core-http/RequestOptionsBase
211
+ * @param options - An options class, typically derived from \@azure/core-rest-pipeline/RequestOptionsBase
193
212
  * @param fn - The function to call with an options class that properly propagates the span context
194
213
  *
195
214
  * @internal
@@ -222,7 +241,7 @@ async function trace(operationName, options, fn, createSpanFn = createSpan) {
222
241
  /**
223
242
  * The AzureLogger used for all clients within the identity package
224
243
  */
225
- const logger = logger$h.createClientLogger("identity");
244
+ const logger = logger$k.createClientLogger("identity");
226
245
  /**
227
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.
228
247
  * @param supportedEnvVars - List of environment variable names
@@ -296,8 +315,8 @@ const noCorrelationId = "noCorrelationId";
296
315
  function getIdentityClientAuthorityHost(options) {
297
316
  // The authorityHost can come from options or from the AZURE_AUTHORITY_HOST environment variable.
298
317
  let authorityHost = options === null || options === void 0 ? void 0 : options.authorityHost;
299
- // The AZURE_AUTHORITY_HOST environment variable can only be provided in NodeJS.
300
- if (coreHttp.isNode) {
318
+ // The AZURE_AUTHORITY_HOST environment variable can only be provided in Node.js.
319
+ if (coreUtil.isNode) {
301
320
  authorityHost = authorityHost !== null && authorityHost !== void 0 ? authorityHost : process.env.AZURE_AUTHORITY_HOST;
302
321
  }
303
322
  // If the authorityHost is not provided, we use the default one from the public cloud: https://login.microsoftonline.com
@@ -310,51 +329,53 @@ function getIdentityClientAuthorityHost(options) {
310
329
  * by calling to the `abortRequests()` method.
311
330
  *
312
331
  */
313
- class IdentityClient extends coreHttp.ServiceClient {
332
+ class IdentityClient extends coreClient.ServiceClient {
314
333
  constructor(options) {
315
- super(undefined, coreHttp.createPipelineFromOptions(Object.assign(Object.assign({}, options), { deserializationOptions: {
316
- expectedContentTypes: {
317
- json: ["application/json", "text/json", "text/plain"]
318
- }
319
- } })));
320
- this.baseUri = this.authorityHost = getIdentityClientAuthorityHost(options);
321
- if (!this.baseUri.startsWith("https:")) {
334
+ var _a;
335
+ const packageDetails = `azsdk-js-identity/2.0.1`;
336
+ const userAgentPrefix = ((_a = options === null || options === void 0 ? void 0 : options.userAgentOptions) === null || _a === void 0 ? void 0 : _a.userAgentPrefix)
337
+ ? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
338
+ : `${packageDetails}`;
339
+ const baseUri = getIdentityClientAuthorityHost(options);
340
+ if (!baseUri.startsWith("https:")) {
322
341
  throw new Error("The authorityHost address must use the 'https' protocol.");
323
342
  }
343
+ super(Object.assign(Object.assign({ requestContentType: "application/json; charset=utf-8" }, options), { userAgentOptions: {
344
+ userAgentPrefix
345
+ }, baseUri }));
346
+ this.authorityHost = baseUri;
324
347
  this.abortControllers = new Map();
325
348
  }
326
- createWebResource(requestOptions) {
327
- const webResource = new coreHttp.WebResource();
328
- webResource.prepare(requestOptions);
329
- return webResource;
330
- }
331
- async sendTokenRequest(webResource, expiresOnParser) {
332
- logger.info(`IdentityClient: sending token request to [${webResource.url}]`);
333
- const response = await this.sendRequest(webResource);
349
+ async sendTokenRequest(request, expiresOnParser) {
350
+ logger.info(`IdentityClient: sending token request to [${request.url}]`);
351
+ const response = await this.sendRequest(request);
334
352
  expiresOnParser =
335
353
  expiresOnParser ||
336
354
  ((responseBody) => {
337
355
  return Date.now() + responseBody.expires_in * 1000;
338
356
  });
339
- if (response.status === 200 || response.status === 201) {
357
+ if (response.bodyAsText && (response.status === 200 || response.status === 201)) {
358
+ const parsedBody = JSON.parse(response.bodyAsText);
359
+ if (!parsedBody.access_token) {
360
+ return null;
361
+ }
340
362
  const token = {
341
363
  accessToken: {
342
- token: response.parsedBody.access_token,
343
- expiresOnTimestamp: expiresOnParser(response.parsedBody)
364
+ token: parsedBody.access_token,
365
+ expiresOnTimestamp: expiresOnParser(parsedBody)
344
366
  },
345
- refreshToken: response.parsedBody.refresh_token
367
+ refreshToken: parsedBody.refresh_token
346
368
  };
347
- logger.info(`IdentityClient: [${webResource.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
369
+ logger.info(`IdentityClient: [${request.url}] token acquired, expires on ${token.accessToken.expiresOnTimestamp}`);
348
370
  return token;
349
371
  }
350
372
  else {
351
- const error = new AuthenticationError(response.status, response.parsedBody || response.bodyAsText);
373
+ const error = new AuthenticationError(response.status, response.bodyAsText);
352
374
  logger.warning(`IdentityClient: authentication error. HTTP status: ${response.status}, ${error.errorResponse.errorDescription}`);
353
375
  throw error;
354
376
  }
355
377
  }
356
378
  async refreshAccessToken(tenantId, clientId, scopes, refreshToken, clientSecret, expiresOnParser, options) {
357
- var _a, _b;
358
379
  if (refreshToken === undefined) {
359
380
  return null;
360
381
  }
@@ -369,23 +390,21 @@ class IdentityClient extends coreHttp.ServiceClient {
369
390
  if (clientSecret !== undefined) {
370
391
  refreshParams.client_secret = clientSecret;
371
392
  }
393
+ const query = new URLSearchParams(refreshParams);
372
394
  try {
373
395
  const urlSuffix = getIdentityTokenEndpointSuffix(tenantId);
374
- const webResource = this.createWebResource({
396
+ const request = coreRestPipeline.createPipelineRequest({
375
397
  url: `${this.authorityHost}/${tenantId}/${urlSuffix}`,
376
398
  method: "POST",
377
- disableJsonStringifyOnBody: true,
378
- deserializationMapper: undefined,
379
- body: qs.stringify(refreshParams),
380
- headers: {
399
+ body: query.toString(),
400
+ abortSignal: options && options.abortSignal,
401
+ headers: coreRestPipeline.createHttpHeaders({
381
402
  Accept: "application/json",
382
403
  "Content-Type": "application/x-www-form-urlencoded"
383
- },
384
- spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
385
- tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext,
386
- abortSignal: options && options.abortSignal
404
+ }),
405
+ tracingOptions: updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions
387
406
  });
388
- const response = await this.sendTokenRequest(webResource, expiresOnParser);
407
+ const response = await this.sendTokenRequest(request, expiresOnParser);
389
408
  logger.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
390
409
  return response;
391
410
  }
@@ -419,13 +438,19 @@ class IdentityClient extends coreHttp.ServiceClient {
419
438
  // since MSAL doesn't allow us to pass options all the way through.
420
439
  generateAbortSignal(correlationId) {
421
440
  const controller = new abortController.AbortController();
422
- const key = correlationId || noCorrelationId;
423
- const controllers = this.abortControllers.get(key) || [];
441
+ const controllers = this.abortControllers.get(correlationId) || [];
424
442
  controllers.push(controller);
425
- this.abortControllers.set(key, controllers);
443
+ this.abortControllers.set(correlationId, controllers);
444
+ const existingOnAbort = controller.signal.onabort;
445
+ controller.signal.onabort = (...params) => {
446
+ this.abortControllers.set(correlationId, undefined);
447
+ if (existingOnAbort) {
448
+ existingOnAbort(...params);
449
+ }
450
+ };
426
451
  return controller.signal;
427
452
  }
428
- abortRequests(correlationId = noCorrelationId) {
453
+ abortRequests(correlationId) {
429
454
  const key = correlationId || noCorrelationId;
430
455
  const controllers = [
431
456
  ...(this.abortControllers.get(key) || []),
@@ -439,37 +464,43 @@ class IdentityClient extends coreHttp.ServiceClient {
439
464
  controller.abort();
440
465
  }
441
466
  this.abortControllers.set(key, undefined);
442
- this.abortControllers.set(noCorrelationId, undefined);
443
467
  }
444
468
  getCorrelationId(options) {
445
469
  var _a;
446
470
  const parameter = (_a = options === null || options === void 0 ? void 0 : options.body) === null || _a === void 0 ? void 0 : _a.split("&").map((part) => part.split("=")).find(([key]) => key === "client-request-id");
447
- return parameter && parameter.length ? parameter[1] : noCorrelationId;
471
+ return parameter && parameter.length ? parameter[1] || noCorrelationId : noCorrelationId;
448
472
  }
449
473
  // The MSAL network module methods follow
450
- sendGetRequestAsync(url, options) {
451
- const webResource = new coreHttp.WebResource(url, "GET", options === null || options === void 0 ? void 0 : options.body, {}, options === null || options === void 0 ? void 0 : options.headers, false, false,
452
- // MSAL doesn't send the correlation ID on the get requests.
453
- this.generateAbortSignal());
454
- return this.sendRequest(webResource).then((response) => {
455
- return {
456
- body: response.parsedBody,
457
- headers: response.headers.rawHeaders(),
458
- status: response.status
459
- };
474
+ async sendGetRequestAsync(url, options) {
475
+ const request = coreRestPipeline.createPipelineRequest({
476
+ url,
477
+ method: "GET",
478
+ body: options === null || options === void 0 ? void 0 : options.body,
479
+ headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
480
+ abortSignal: this.generateAbortSignal(noCorrelationId)
460
481
  });
482
+ const response = await this.sendRequest(request);
483
+ return {
484
+ body: response.bodyAsText ? JSON.parse(response.bodyAsText) : undefined,
485
+ headers: response.headers.toJSON(),
486
+ status: response.status
487
+ };
461
488
  }
462
- sendPostRequestAsync(url, options) {
463
- const webResource = new coreHttp.WebResource(url, "POST", options === null || options === void 0 ? void 0 : options.body, {}, options === null || options === void 0 ? void 0 : options.headers, false, false,
464
- // MSAL doesn't send the correlation ID on the get requests.
465
- this.generateAbortSignal(this.getCorrelationId(options)));
466
- return this.sendRequest(webResource).then((response) => {
467
- return {
468
- body: response.parsedBody,
469
- headers: response.headers.rawHeaders(),
470
- status: response.status
471
- };
489
+ async sendPostRequestAsync(url, options) {
490
+ const request = coreRestPipeline.createPipelineRequest({
491
+ url,
492
+ method: "POST",
493
+ body: options === null || options === void 0 ? void 0 : options.body,
494
+ headers: coreRestPipeline.createHttpHeaders(options === null || options === void 0 ? void 0 : options.headers),
495
+ // MSAL doesn't send the correlation ID on the get requests.
496
+ abortSignal: this.generateAbortSignal(this.getCorrelationId(options))
472
497
  });
498
+ const response = await this.sendRequest(request);
499
+ return {
500
+ body: response.bodyAsText ? JSON.parse(response.bodyAsText) : undefined,
501
+ headers: response.headers.toJSON(),
502
+ status: response.status
503
+ };
473
504
  }
474
505
  }
475
506
 
@@ -497,28 +528,6 @@ function resolveTenantId(logger, tenantId, clientId) {
497
528
  return "organizations";
498
529
  }
499
530
 
500
- // Copyright (c) Microsoft Corporation.
501
- // Licensed under the MIT license.
502
- /**
503
- * Error used to enforce authentication after trying to retrieve a token silently.
504
- */
505
- class AuthenticationRequiredError extends Error {
506
- constructor(
507
- /**
508
- * The list of scopes for which the token will have access.
509
- */
510
- scopes,
511
- /**
512
- * The options used to configure the getToken request.
513
- */
514
- getTokenOptions = {}, message) {
515
- super(message);
516
- this.scopes = scopes;
517
- this.getTokenOptions = getTokenOptions;
518
- this.name = "AuthenticationRequiredError";
519
- }
520
- }
521
-
522
531
  // Copyright (c) Microsoft Corporation.
523
532
  /**
524
533
  * Latest AuthenticationRecord version
@@ -532,7 +541,11 @@ const LatestAuthenticationRecordVersion = "1.0";
532
541
  function ensureValidMsalToken(scopes, logger, msalToken, getTokenOptions) {
533
542
  const error = (message) => {
534
543
  logger.getToken.info(message);
535
- 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
+ });
536
549
  };
537
550
  if (!msalToken) {
538
551
  throw error("No response");
@@ -548,7 +561,10 @@ function ensureValidMsalToken(scopes, logger, msalToken, getTokenOptions) {
548
561
  * Generates a valid authority by combining a host with a tenantId.
549
562
  * @internal
550
563
  */
551
- function getAuthority(tenantId, host = DefaultAuthorityHost) {
564
+ function getAuthority(tenantId, host) {
565
+ if (!host) {
566
+ host = DefaultAuthorityHost;
567
+ }
552
568
  if (host.endsWith("/")) {
553
569
  return host + tenantId;
554
570
  }
@@ -558,8 +574,9 @@ function getAuthority(tenantId, host = DefaultAuthorityHost) {
558
574
  }
559
575
  /**
560
576
  * Generates the known authorities.
561
- * If the tenantId is "adfs", we will return an array with the authorityHost as the only known authority.
562
- * Otherwise, it is safe to return an empty array.
577
+ * If the Tenant Id is `adfs`, the authority can't be validated since the format won't match the expected one.
578
+ * For that reason, we have to force MSAL to disable validating the authority
579
+ * by sending it within the known authorities in the MSAL configuration.
563
580
  * @internal
564
581
  */
565
582
  function getKnownAuthorities(tenantId, authorityHost) {
@@ -573,7 +590,7 @@ function getKnownAuthorities(tenantId, authorityHost) {
573
590
  * @param logger - The logger of the credential.
574
591
  * @internal
575
592
  */
576
- const defaultLoggerCallback = (logger, platform = coreHttp.isNode ? "Node" : "Browser") => (level, message, containsPii) => {
593
+ const defaultLoggerCallback = (logger, platform = coreUtil.isNode ? "Node" : "Browser") => (level, message, containsPii) => {
577
594
  if (containsPii) {
578
595
  return;
579
596
  }
@@ -656,7 +673,7 @@ class MsalBaseUtilities {
656
673
  error.name === "AbortError") {
657
674
  return error;
658
675
  }
659
- return new AuthenticationRequiredError(scopes, getTokenOptions, error.message);
676
+ return new AuthenticationRequiredError({ scopes, getTokenOptions, message: error.message });
660
677
  }
661
678
  }
662
679
  // transformations.ts
@@ -720,6 +737,40 @@ function deserializeAuthenticationRecord(serializedRecord) {
720
737
  }
721
738
 
722
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;
723
774
  (function (RegionalAuthority) {
724
775
  /** Instructs MSAL to attempt to discover the region */
725
776
  RegionalAuthority["AutoDiscoverRegion"] = "AutoDiscoverRegion";
@@ -827,31 +878,7 @@ function deserializeAuthenticationRecord(serializedRecord) {
827
878
  RegionalAuthority["GovernmentUSDodEast"] = "usdodeast";
828
879
  /** Uses the {@link RegionalAuthority} for the Azure 'usdodcentral' region. */
829
880
  RegionalAuthority["GovernmentUSDodCentral"] = "usdodcentral";
830
- })(exports.RegionalAuthority || (exports.RegionalAuthority = {}));
831
-
832
- // Copyright (c) Microsoft Corporation.
833
- // Licensed under the MIT license.
834
- /**
835
- * @internal
836
- */
837
- 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.";
838
- /**
839
- * Verifies whether locally assigned tenants are equal to tenants received through getToken.
840
- * Returns the appropriate tenant.
841
- * @internal
842
- */
843
- function processMultiTenantRequest(tenantId, allowMultiTenantAuthentication, getTokenOptions) {
844
- if (!allowMultiTenantAuthentication &&
845
- (getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId) &&
846
- tenantId &&
847
- getTokenOptions.tenantId !== tenantId) {
848
- throw new Error(multiTenantErrorMessage);
849
- }
850
- if (allowMultiTenantAuthentication && (getTokenOptions === null || getTokenOptions === void 0 ? void 0 : getTokenOptions.tenantId)) {
851
- return getTokenOptions.tenantId;
852
- }
853
- return tenantId;
854
- }
881
+ })(RegionalAuthority || (RegionalAuthority = {}));
855
882
 
856
883
  // Copyright (c) Microsoft Corporation.
857
884
  /**
@@ -869,7 +896,7 @@ const msalNodeFlowCacheControl = {
869
896
  }
870
897
  };
871
898
  /**
872
- * MSAL partial base client for NodeJS.
899
+ * MSAL partial base client for Node.js.
873
900
  *
874
901
  * It completes the input configuration with some default values.
875
902
  * It also provides with utility protected methods that can be used from any of the clients,
@@ -884,22 +911,26 @@ class MsalNode extends MsalBaseUtilities {
884
911
  this.requiresConfidential = false;
885
912
  this.msalConfig = this.defaultNodeMsalConfig(options);
886
913
  this.tenantId = resolveTenantId(options.logger, options.tenantId, options.clientId);
887
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
888
914
  this.clientId = this.msalConfig.auth.clientId;
889
915
  // If persistence has been configured
890
916
  if (persistenceProvider !== undefined && ((_a = options.tokenCachePersistenceOptions) === null || _a === void 0 ? void 0 : _a.enabled)) {
891
917
  this.createCachePlugin = () => persistenceProvider(options.tokenCachePersistenceOptions);
892
918
  }
893
919
  else if ((_b = options.tokenCachePersistenceOptions) === null || _b === void 0 ? void 0 : _b.enabled) {
894
- 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(" "));
895
926
  }
896
927
  this.azureRegion = (_c = options.regionalAuthority) !== null && _c !== void 0 ? _c : process.env.AZURE_REGIONAL_AUTHORITY_NAME;
897
- if (this.azureRegion === exports.RegionalAuthority.AutoDiscoverRegion) {
928
+ if (this.azureRegion === RegionalAuthority.AutoDiscoverRegion) {
898
929
  this.azureRegion = "AUTO_DISCOVER";
899
930
  }
900
931
  }
901
932
  /**
902
- * Generates a MSAL configuration that generally works for NodeJS
933
+ * Generates a MSAL configuration that generally works for Node.js
903
934
  */
904
935
  defaultNodeMsalConfig(options) {
905
936
  const clientId = options.clientId || DeveloperSignOnClientId;
@@ -907,11 +938,16 @@ class MsalNode extends MsalBaseUtilities {
907
938
  this.authorityHost = options.authorityHost || process.env.AZURE_AUTHORITY_HOST;
908
939
  const authority = getAuthority(tenantId, this.authorityHost);
909
940
  this.identityClient = new IdentityClient(Object.assign(Object.assign({}, options.tokenCredentialOptions), { authorityHost: authority }));
941
+ let clientCapabilities = ["CP1"];
942
+ if (process.env.AZURE_IDENTITY_DISABLE_CP1) {
943
+ clientCapabilities = [];
944
+ }
910
945
  return {
911
946
  auth: {
912
947
  clientId,
913
948
  authority,
914
- knownAuthorities: getKnownAuthorities(tenantId, authority)
949
+ knownAuthorities: getKnownAuthorities(tenantId, authority),
950
+ clientCapabilities
915
951
  },
916
952
  // Cache is defined in this.prepare();
917
953
  system: {
@@ -1005,7 +1041,11 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
1005
1041
  var _a, _b;
1006
1042
  await this.getActiveAccount();
1007
1043
  if (!this.account) {
1008
- 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
+ });
1009
1049
  }
1010
1050
  const silentRequest = {
1011
1051
  // To be able to re-use the account, the Token Cache must also have been provided.
@@ -1028,21 +1068,27 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov
1028
1068
  * If disableAutomaticAuthentication is sent through the constructor, it will prevent MSAL from requesting the user input.
1029
1069
  */
1030
1070
  async getToken(scopes, options = {}) {
1031
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
1032
- this.tenantId;
1071
+ const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
1033
1072
  options.authority = getAuthority(tenantId, this.authorityHost);
1034
1073
  options.correlationId = (options === null || options === void 0 ? void 0 : options.correlationId) || this.generateUuid();
1035
1074
  await this.init(options);
1036
- return this.getTokenSilent(scopes, options).catch((err) => {
1075
+ try {
1076
+ return await this.getTokenSilent(scopes, options);
1077
+ }
1078
+ catch (err) {
1037
1079
  if (err.name !== "AuthenticationRequiredError") {
1038
1080
  throw err;
1039
1081
  }
1040
1082
  if (options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication) {
1041
- 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
+ });
1042
1088
  }
1043
1089
  this.logger.info(`Silent authentication failed, falling back to interactive method.`);
1044
1090
  return this.doGetToken(scopes, options);
1045
- });
1091
+ }
1046
1092
  }
1047
1093
  }
1048
1094
 
@@ -1107,7 +1153,7 @@ function getPropertyFromVSCode(property) {
1107
1153
  }
1108
1154
  }
1109
1155
  /**
1110
- * 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'.
1111
1157
  * Once the user has logged in via the extension, this credential can share the same refresh token
1112
1158
  * that is cached by the extension.
1113
1159
  */
@@ -1115,6 +1161,11 @@ class VisualStudioCodeCredential {
1115
1161
  /**
1116
1162
  * Creates an instance of VisualStudioCodeCredential to use for automatically authenticating via VSCode.
1117
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
+ *
1118
1169
  * @param options - Options for configuring the client which makes the authentication request.
1119
1170
  */
1120
1171
  constructor(options) {
@@ -1131,7 +1182,6 @@ class VisualStudioCodeCredential {
1131
1182
  else {
1132
1183
  this.tenantId = CommonTenantId;
1133
1184
  }
1134
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
1135
1185
  checkUnsupportedTenant(this.tenantId);
1136
1186
  }
1137
1187
  /**
@@ -1165,10 +1215,14 @@ class VisualStudioCodeCredential {
1165
1215
  async getToken(scopes, options) {
1166
1216
  var _a, _b;
1167
1217
  await this.prepareOnce();
1168
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
1169
- this.tenantId;
1218
+ const tenantId = processMultiTenantRequest(this.tenantId, options) || this.tenantId;
1170
1219
  if (findCredentials === undefined) {
1171
- 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(" "));
1172
1226
  }
1173
1227
  let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
1174
1228
  // Check to make sure the scope we get back is a valid scope
@@ -1198,13 +1252,13 @@ class VisualStudioCodeCredential {
1198
1252
  return tokenResponse.accessToken;
1199
1253
  }
1200
1254
  else {
1201
- 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.");
1202
1256
  logger$1.getToken.info(formatError(scopes, error));
1203
1257
  throw error;
1204
1258
  }
1205
1259
  }
1206
1260
  else {
1207
- 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.");
1208
1262
  logger$1.getToken.info(formatError(scopes, error));
1209
1263
  throw error;
1210
1264
  }
@@ -1213,17 +1267,17 @@ class VisualStudioCodeCredential {
1213
1267
 
1214
1268
  // Copyright (c) Microsoft Corporation.
1215
1269
  /**
1216
- * The context passed to an Identity Extension. This contains objects that
1217
- * 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.
1218
1272
  * @internal
1219
1273
  */
1220
- const extensionContext = {
1274
+ const pluginContext = {
1221
1275
  cachePluginControl: msalNodeFlowCacheControl,
1222
1276
  vsCodeCredentialControl: vsCodeCredentialControl
1223
1277
  };
1224
1278
  /**
1225
- * Extend Azure Identity with additional functionality. Pass an extension from
1226
- * an extension package, such as:
1279
+ * Extend Azure Identity with additional functionality. Pass a plugin from
1280
+ * a plugin package, such as:
1227
1281
  *
1228
1282
  * - `@azure/identity-cache-persistence`: provides persistent token caching
1229
1283
  * - `@azure/identity-vscode`: provides the dependencies of
@@ -1232,12 +1286,12 @@ const extensionContext = {
1232
1286
  * Example:
1233
1287
  *
1234
1288
  * ```javascript
1235
- * import { cachePersistenceExtension } from "@azure/identity-cache-persistence";
1289
+ * import { cachePersistencePlugin } from "@azure/identity-cache-persistence";
1236
1290
  *
1237
- * import { useIdentityExtension, DefaultAzureCredential } from "@azure/identity";
1238
- * useIdentityExtension(persistence);
1291
+ * import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
1292
+ * useIdentityPlugin(cachePersistencePlugin);
1239
1293
  *
1240
- * // The extension has the capability to extend `DefaultAzureCredential` and to
1294
+ * // The plugin has the capability to extend `DefaultAzureCredential` and to
1241
1295
  * // add middleware to the underlying credentials, such as persistence.
1242
1296
  * const credential = new DefaultAzureCredential({
1243
1297
  * tokenCachePersistenceOptions: {
@@ -1246,10 +1300,10 @@ const extensionContext = {
1246
1300
  * });
1247
1301
  * ```
1248
1302
  *
1249
- * @param extension - the extension to register
1303
+ * @param plugin - the plugin to register
1250
1304
  */
1251
- function useIdentityExtension(extension) {
1252
- extension(extensionContext);
1305
+ function useIdentityPlugin(plugin) {
1306
+ plugin(pluginContext);
1253
1307
  }
1254
1308
 
1255
1309
  // Copyright (c) Microsoft Corporation.
@@ -1299,7 +1353,7 @@ class ChainedTokenCredential {
1299
1353
  let token = null;
1300
1354
  let successfulCredentialName = "";
1301
1355
  const errors = [];
1302
- const { span, updatedOptions } = createSpan("ChainedTokenCredential-getToken", options);
1356
+ const { span, updatedOptions } = createSpan("ChainedTokenCredential.getToken", options);
1303
1357
  for (let i = 0; i < this._sources.length && token === null; i++) {
1304
1358
  try {
1305
1359
  token = await this._sources[i].getToken(scopes, updatedOptions);
@@ -1317,7 +1371,7 @@ class ChainedTokenCredential {
1317
1371
  }
1318
1372
  }
1319
1373
  if (!token && errors.length > 0) {
1320
- const err = new AggregateAuthenticationError(errors);
1374
+ const err = new AggregateAuthenticationError(errors, "ChainedTokenCredential authentication failed.");
1321
1375
  span.setStatus({
1322
1376
  code: coreTracing.SpanStatusCode.ERROR,
1323
1377
  message: err.message
@@ -1386,15 +1440,15 @@ const cliCredentialInternals = {
1386
1440
  }
1387
1441
  return new Promise((resolve, reject) => {
1388
1442
  try {
1389
- child_process.execFile("az", [
1443
+ child_process__default.execFile("az", [
1390
1444
  "account",
1391
1445
  "get-access-token",
1392
1446
  "--output",
1393
1447
  "json",
1394
1448
  "--resource",
1395
- ...tenantSection,
1396
- resource
1397
- ], { cwd: cliCredentialInternals.getSafeWorkingDir() }, (error, stdout, stderr) => {
1449
+ resource,
1450
+ ...tenantSection
1451
+ ], { cwd: cliCredentialInternals.getSafeWorkingDir(), shell: true }, (error, stdout, stderr) => {
1398
1452
  resolve({ stdout: stdout, stderr: stderr, error });
1399
1453
  });
1400
1454
  }
@@ -1410,18 +1464,18 @@ const logger$3 = credentialLogger("AzureCliCredential");
1410
1464
  * via the Azure CLI ('az') commandline tool.
1411
1465
  * To do so, it will read the user access token and expire time
1412
1466
  * with Azure CLI command "az account get-access-token".
1413
- * To be able to use this credential, ensure that you have already logged
1414
- * in via the 'az' tool using the command "az login" from the commandline.
1415
1467
  */
1416
1468
  class AzureCliCredential {
1417
1469
  /**
1418
1470
  * Creates an instance of the {@link AzureCliCredential}.
1419
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
+ *
1420
1475
  * @param options - Options, to optionally allow multi-tenant requests.
1421
1476
  */
1422
1477
  constructor(options) {
1423
1478
  this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
1424
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
1425
1479
  }
1426
1480
  /**
1427
1481
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -1432,7 +1486,7 @@ class AzureCliCredential {
1432
1486
  * TokenCredential implementation might make.
1433
1487
  */
1434
1488
  async getToken(scopes, options) {
1435
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options);
1489
+ const tenantId = processMultiTenantRequest(this.tenantId, options);
1436
1490
  if (tenantId) {
1437
1491
  checkTenantId(logger$3, tenantId);
1438
1492
  }
@@ -1441,7 +1495,7 @@ class AzureCliCredential {
1441
1495
  ensureValidScope(scope, logger$3);
1442
1496
  const resource = getScopeResource(scope);
1443
1497
  let responseData = "";
1444
- const { span } = createSpan("AzureCliCredential-getToken", options);
1498
+ const { span } = createSpan("AzureCliCredential.getToken", options);
1445
1499
  try {
1446
1500
  const obj = await cliCredentialInternals.getAzureCliAccessToken(resource, tenantId);
1447
1501
  if (obj.stderr) {
@@ -1558,7 +1612,8 @@ const powerShellErrors = {
1558
1612
  */
1559
1613
  const powerShellPublicErrorMessages = {
1560
1614
  login: "Please run 'Connect-AzAccount' from PowerShell to authenticate before using this credential.",
1561
- 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.`
1562
1617
  };
1563
1618
  // PowerShell Azure User not logged in error check.
1564
1619
  const isLoginError = (err) => err.message.match(`(.*)${powerShellErrors.login}(.*)`);
@@ -1577,22 +1632,21 @@ if (isWindows) {
1577
1632
  * This credential will use the currently logged-in user information from the
1578
1633
  * Azure PowerShell module. To do so, it will read the user access token and
1579
1634
  * expire time with Azure PowerShell command `Get-AzAccessToken -ResourceUrl {ResourceScope}`
1580
- *
1581
- * To be able to use this credential:
1582
- * - Install the Azure Az PowerShell module with:
1583
- * `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
1584
- * - You have already logged in to Azure PowerShell using the command
1585
- * `Connect-AzAccount` from the command line.
1586
1635
  */
1587
1636
  class AzurePowerShellCredential {
1588
1637
  /**
1589
- * 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.
1590
1645
  *
1591
1646
  * @param options - Options, to optionally allow multi-tenant requests.
1592
1647
  */
1593
1648
  constructor(options) {
1594
1649
  this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
1595
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
1596
1650
  }
1597
1651
  /**
1598
1652
  * Gets the access token from Azure PowerShell
@@ -1633,7 +1687,7 @@ class AzurePowerShellCredential {
1633
1687
  throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
1634
1688
  }
1635
1689
  }
1636
- 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`);
1637
1691
  }
1638
1692
  /**
1639
1693
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -1644,7 +1698,7 @@ class AzurePowerShellCredential {
1644
1698
  */
1645
1699
  async getToken(scopes, options = {}) {
1646
1700
  return trace(`${this.constructor.name}.getToken`, options, async () => {
1647
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options);
1701
+ const tenantId = processMultiTenantRequest(this.tenantId, options);
1648
1702
  if (tenantId) {
1649
1703
  checkTenantId(logger$4, tenantId);
1650
1704
  }
@@ -1671,7 +1725,7 @@ class AzurePowerShellCredential {
1671
1725
  logger$4.getToken.info(formatError(scope, error));
1672
1726
  throw error;
1673
1727
  }
1674
- const error = new CredentialUnavailableError(err);
1728
+ const error = new CredentialUnavailableError(`${err}. ${powerShellPublicErrorMessages.troubleshoot}`);
1675
1729
  logger$4.getToken.info(formatError(scope, error));
1676
1730
  throw error;
1677
1731
  }
@@ -1730,6 +1784,9 @@ class ClientSecretCredential {
1730
1784
  * @param options - Options for configuring the client which makes the authentication request.
1731
1785
  */
1732
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
+ }
1733
1790
  this.msalFlow = new MsalClientSecret(Object.assign(Object.assign({}, options), { logger: logger$5,
1734
1791
  clientId,
1735
1792
  tenantId,
@@ -1752,6 +1809,41 @@ class ClientSecretCredential {
1752
1809
  }
1753
1810
 
1754
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
+ }
1755
1847
  /**
1756
1848
  * MSAL client certificate client. Calls to MSAL's confidential application's `acquireTokenByClientCredential` during `doGetToken`.
1757
1849
  * @internal
@@ -1760,40 +1852,24 @@ class MsalClientCertificate extends MsalNode {
1760
1852
  constructor(options) {
1761
1853
  super(options);
1762
1854
  this.requiresConfidential = true;
1855
+ this.configuration = options.configuration;
1763
1856
  this.sendCertificateChain = options.sendCertificateChain;
1764
- const parts = this.parseCertificate(options.certificatePath);
1765
- this.msalConfig.auth.clientCertificate = {
1766
- thumbprint: parts.thumbprint,
1767
- privateKey: parts.certificateContents,
1768
- x5c: parts.x5c
1769
- };
1770
1857
  }
1771
- parseCertificate(certificatePath) {
1772
- const certificateParts = {};
1773
- certificateParts.certificateContents = fs.readFileSync(certificatePath, "utf8");
1774
- if (this.sendCertificateChain) {
1775
- certificateParts.x5c = certificateParts.certificateContents;
1776
- }
1777
- const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
1778
- const publicKeys = [];
1779
- // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
1780
- let match;
1781
- do {
1782
- match = certificatePattern.exec(certificateParts.certificateContents);
1783
- if (match) {
1784
- publicKeys.push(match[3]);
1785
- }
1786
- } while (match);
1787
- if (publicKeys.length === 0) {
1788
- 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) {
1789
1869
  this.logger.info(formatError("", error));
1790
1870
  throw error;
1791
1871
  }
1792
- certificateParts.thumbprint = crypto.createHash("sha1")
1793
- .update(Buffer.from(publicKeys[0], "base64"))
1794
- .digest("hex")
1795
- .toUpperCase();
1796
- return certificateParts;
1872
+ return super.init(options);
1797
1873
  }
1798
1874
  async doGetToken(scopes, options = {}) {
1799
1875
  try {
@@ -1815,7 +1891,8 @@ class MsalClientCertificate extends MsalNode {
1815
1891
  }
1816
1892
 
1817
1893
  // Copyright (c) Microsoft Corporation.
1818
- const logger$6 = credentialLogger("ClientCertificateCredential");
1894
+ const credentialName = "ClientCertificateCredential";
1895
+ const logger$6 = credentialLogger(credentialName);
1819
1896
  /**
1820
1897
  * Enables authentication to Azure Active Directory using a PEM-encoded
1821
1898
  * certificate that is assigned to an App Registration. More information
@@ -1825,17 +1902,22 @@ const logger$6 = credentialLogger("ClientCertificateCredential");
1825
1902
  *
1826
1903
  */
1827
1904
  class ClientCertificateCredential {
1828
- /**
1829
- * Creates an instance of the ClientCertificateCredential with the details
1830
- * needed to authenticate against Azure Active Directory with a certificate.
1831
- *
1832
- * @param tenantId - The Azure Active Directory tenant (directory) ID.
1833
- * @param clientId - The client (application) ID of an App Registration in the tenant.
1834
- * @param certificatePath - The path to a PEM-encoded public/private key certificate on the filesystem.
1835
- * @param options - Options for configuring the client which makes the authentication request.
1836
- */
1837
- constructor(tenantId, clientId, certificatePath, options = {}) {
1838
- 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,
1839
1921
  logger: logger$6,
1840
1922
  clientId,
1841
1923
  tenantId, sendCertificateChain: options.sendCertificateChain, tokenCredentialOptions: options }));
@@ -1849,7 +1931,7 @@ class ClientCertificateCredential {
1849
1931
  * TokenCredential implementation might make.
1850
1932
  */
1851
1933
  async getToken(scopes, options = {}) {
1852
- return trace(`${this.constructor.name}.getToken`, options, async (newOptions) => {
1934
+ return trace(`${credentialName}.getToken`, options, async (newOptions) => {
1853
1935
  const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
1854
1936
  return this.msalFlow.getToken(arrayScopes, newOptions);
1855
1937
  });
@@ -1893,8 +1975,6 @@ const logger$7 = credentialLogger("UsernamePasswordCredential");
1893
1975
  * trust so you should only use it when other, more secure credential
1894
1976
  * types can't be used.
1895
1977
  */
1896
- // We'll be using InteractiveCredential as the base of this class, which requires us to support authenticate(),
1897
- // to reduce the number of times we send the password over the network.
1898
1978
  class UsernamePasswordCredential {
1899
1979
  /**
1900
1980
  * Creates an instance of the UsernamePasswordCredential with the details
@@ -1908,6 +1988,9 @@ class UsernamePasswordCredential {
1908
1988
  * @param options - Options for configuring the client which makes the authentication request.
1909
1989
  */
1910
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
+ }
1911
1994
  this.msalFlow = new MsalUsernamePassword(Object.assign(Object.assign({}, options), { logger: logger$7,
1912
1995
  clientId,
1913
1996
  tenantId,
@@ -1953,23 +2036,7 @@ const AllSupportedEnvironmentVariables = [
1953
2036
  const logger$8 = credentialLogger("EnvironmentCredential");
1954
2037
  /**
1955
2038
  * Enables authentication to Azure Active Directory using client secret
1956
- * details configured in the following environment variables:
1957
- *
1958
- * Required environment variables:
1959
- * - `AZURE_TENANT_ID`: The Azure Active Directory tenant (directory) ID.
1960
- * - `AZURE_CLIENT_ID`: The client (application) ID of an App Registration in the tenant.
1961
- *
1962
- * Environment variables used for client credential authentication:
1963
- * - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
1964
- * - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
1965
- *
1966
- * Alternatively, users can provide environment variables for username and password authentication:
1967
- * - `AZURE_USERNAME`: Username to authenticate with.
1968
- * - `AZURE_PASSWORD`: Password to authenticate with.
1969
- *
1970
- * This credential ultimately uses a {@link ClientSecretCredential} to
1971
- * perform the authentication using these details. Please consult the
1972
- * documentation of that class for more details.
2039
+ * details configured in environment variables
1973
2040
  */
1974
2041
  class EnvironmentCredential {
1975
2042
  /**
@@ -2009,7 +2076,7 @@ class EnvironmentCredential {
2009
2076
  const certificatePath = process.env.AZURE_CLIENT_CERTIFICATE_PATH;
2010
2077
  if (tenantId && clientId && certificatePath) {
2011
2078
  logger$8.info(`Invoking ClientCertificateCredential with tenant ID: ${tenantId}, clientId: ${clientId} and certificatePath: ${certificatePath}`);
2012
- this._credential = new ClientCertificateCredential(tenantId, clientId, certificatePath, options);
2079
+ this._credential = new ClientCertificateCredential(tenantId, clientId, { certificatePath }, options);
2013
2080
  return;
2014
2081
  }
2015
2082
  const username = process.env.AZURE_USERNAME;
@@ -2035,7 +2102,7 @@ class EnvironmentCredential {
2035
2102
  }
2036
2103
  catch (err) {
2037
2104
  const authenticationError = new AuthenticationError(400, {
2038
- error: "EnvironmentCredential authentication failed.",
2105
+ error: "EnvironmentCredential authentication failed. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.",
2039
2106
  error_description: err.message
2040
2107
  .toString()
2041
2108
  .split("More details:")
@@ -2045,7 +2112,7 @@ class EnvironmentCredential {
2045
2112
  throw authenticationError;
2046
2113
  }
2047
2114
  }
2048
- 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.");
2049
2116
  });
2050
2117
  }
2051
2118
  }
@@ -2053,16 +2120,26 @@ class EnvironmentCredential {
2053
2120
  // Copyright (c) Microsoft Corporation.
2054
2121
  // Licensed under the MIT license.
2055
2122
  const DefaultScopeSuffix = "/.default";
2056
- const imdsEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token";
2123
+ const imdsHost = "http://169.254.169.254";
2124
+ const imdsEndpointPath = "/metadata/identity/oauth2/token";
2057
2125
  const imdsApiVersion = "2018-02-01";
2058
2126
  const azureArcAPIVersion = "2019-11-01";
2127
+ const azureFabricVersion = "2019-07-01-preview";
2059
2128
 
2060
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
+ */
2061
2138
  function mapScopesToResource(scopes) {
2062
2139
  let scope = "";
2063
2140
  if (Array.isArray(scopes)) {
2064
2141
  if (scopes.length !== 1) {
2065
- throw new Error("To convert to a resource string the specified array must be exactly length 1");
2142
+ return;
2066
2143
  }
2067
2144
  scope = scopes[0];
2068
2145
  }
@@ -2074,81 +2151,177 @@ function mapScopesToResource(scopes) {
2074
2151
  }
2075
2152
  return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
2076
2153
  }
2077
- async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}) {
2078
- const webResource = identityClient.createWebResource(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal, spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions, tracingContext: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.tracingContext }, requestOptions));
2079
- const tokenResponse = await identityClient.sendTokenRequest(webResource, expiresInParser);
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
+ }
2159
+ const tokenResponse = await identityClient.sendTokenRequest(request, expiresInParser);
2080
2160
  return (tokenResponse && tokenResponse.accessToken) || null;
2081
2161
  }
2082
2162
 
2083
2163
  // Copyright (c) Microsoft Corporation.
2084
- const logger$9 = credentialLogger("ManagedIdentityCredential - CloudShellMSI");
2164
+ const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
2165
+ const logger$9 = credentialLogger(msiName);
2166
+ function expiresInParser(requestBody) {
2167
+ // Parse a date format like "06/20/2019 02:57:58 +00:00" and
2168
+ // convert it into a JavaScript-formatted date
2169
+ return Date.parse(requestBody.expires_on);
2170
+ }
2171
+ function prepareRequestOptions(scopes, clientId) {
2172
+ const resource = mapScopesToResource(scopes);
2173
+ if (!resource) {
2174
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
2175
+ }
2176
+ const queryParameters = {
2177
+ resource,
2178
+ "api-version": "2017-09-01"
2179
+ };
2180
+ if (clientId) {
2181
+ queryParameters.clientid = clientId;
2182
+ }
2183
+ const query = new URLSearchParams(queryParameters);
2184
+ // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2185
+ if (!process.env.MSI_ENDPOINT) {
2186
+ throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
2187
+ }
2188
+ if (!process.env.MSI_SECRET) {
2189
+ throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
2190
+ }
2191
+ return {
2192
+ url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
2193
+ method: "GET",
2194
+ headers: coreRestPipeline.createHttpHeaders({
2195
+ Accept: "application/json",
2196
+ secret: process.env.MSI_SECRET
2197
+ })
2198
+ };
2199
+ }
2200
+ const appServiceMsi2017 = {
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
+ }
2207
+ const env = process.env;
2208
+ const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
2209
+ if (!result) {
2210
+ logger$9.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
2211
+ }
2212
+ return result;
2213
+ },
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);
2218
+ }
2219
+ };
2220
+
2221
+ // Copyright (c) Microsoft Corporation.
2222
+ const msiName$1 = "ManagedIdentityCredential - CloudShellMSI";
2223
+ const logger$a = credentialLogger(msiName$1);
2085
2224
  // Cloud Shell MSI doesn't have a special expiresIn parser.
2086
- const expiresInParser = undefined;
2087
- function prepareRequestOptions(resource, clientId) {
2225
+ const expiresInParser$1 = undefined;
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
+ }
2088
2231
  const body = {
2089
2232
  resource
2090
2233
  };
2091
2234
  if (clientId) {
2092
2235
  body.client_id = clientId;
2093
2236
  }
2237
+ // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2238
+ if (!process.env.MSI_ENDPOINT) {
2239
+ throw new Error(`${msiName$1}: Missing environment variable: MSI_ENDPOINT`);
2240
+ }
2241
+ const params = new URLSearchParams(body);
2094
2242
  return {
2095
2243
  url: process.env.MSI_ENDPOINT,
2096
2244
  method: "POST",
2097
- body: qs.stringify(body),
2098
- headers: {
2245
+ body: params.toString(),
2246
+ headers: coreRestPipeline.createHttpHeaders({
2099
2247
  Accept: "application/json",
2100
- Metadata: true,
2248
+ Metadata: "true",
2101
2249
  "Content-Type": "application/x-www-form-urlencoded"
2102
- }
2250
+ })
2103
2251
  };
2104
2252
  }
2105
2253
  const cloudShellMsi = {
2106
- 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
+ }
2107
2260
  const result = Boolean(process.env.MSI_ENDPOINT);
2108
2261
  if (!result) {
2109
- logger$9.info("The Azure Cloud Shell MSI is unavailable.");
2262
+ logger$a.info(`${msiName$1}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
2110
2263
  }
2111
2264
  return result;
2112
2265
  },
2113
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2114
- logger$9.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.`);
2115
- return msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, 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);
2116
2270
  }
2117
2271
  };
2118
2272
 
2119
2273
  // Copyright (c) Microsoft Corporation.
2120
- const logger$a = credentialLogger("ManagedIdentityCredential - IMDS");
2121
- function expiresInParser$1(requestBody) {
2274
+ const msiName$2 = "ManagedIdentityCredential - IMDS";
2275
+ const logger$b = credentialLogger(msiName$2);
2276
+ function expiresInParser$2(requestBody) {
2122
2277
  if (requestBody.expires_on) {
2123
2278
  // Use the expires_on timestamp if it's available
2124
2279
  const expires = +requestBody.expires_on * 1000;
2125
- logger$a.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})`);
2126
2281
  return expires;
2127
2282
  }
2128
2283
  else {
2129
2284
  // If these aren't possible, use expires_in and calculate a timestamp
2130
2285
  const expires = Date.now() + requestBody.expires_in * 1000;
2131
- logger$a.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})`);
2132
2287
  return expires;
2133
2288
  }
2134
2289
  }
2135
- function prepareRequestOptions$1(resource, clientId) {
2290
+ function prepareRequestOptions$2(scopes, clientId, options) {
2136
2291
  var _a;
2137
- const queryParameters = {
2138
- resource,
2139
- "api-version": imdsApiVersion
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()}`;
2310
+ }
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"
2140
2315
  };
2141
- if (clientId) {
2142
- queryParameters.client_id = clientId;
2316
+ // Remove the Metadata header to invoke a request error from some IMDS endpoints.
2317
+ if (skipMetadataHeader) {
2318
+ delete rawHeaders.Metadata;
2143
2319
  }
2144
2320
  return {
2145
- url: (_a = process.env.AZURE_POD_IDENTITY_TOKEN_URL) !== null && _a !== void 0 ? _a : imdsEndpoint,
2321
+ // In this case, the `?` should be added in the "query" variable `skipQuery` is not set.
2322
+ url: `${url}${query}`,
2146
2323
  method: "GET",
2147
- queryParameters,
2148
- headers: {
2149
- Accept: "application/json",
2150
- Metadata: true
2151
- }
2324
+ headers: coreRestPipeline.createHttpHeaders(rawHeaders)
2152
2325
  };
2153
2326
  }
2154
2327
  // 800ms -> 1600ms -> 3200ms
@@ -2158,43 +2331,45 @@ const imdsMsiRetryConfig = {
2158
2331
  intervalIncrement: 2
2159
2332
  };
2160
2333
  const imdsMsi = {
2161
- async isAvailable(identityClient, resource, clientId, getTokenOptions) {
2162
- var _a, _b, _c;
2163
- const { span, updatedOptions } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
2334
+ async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
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
+ }
2341
+ const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
2164
2342
  // if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
2165
- if (process.env.AZURE_POD_IDENTITY_TOKEN_URL) {
2343
+ if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
2166
2344
  return true;
2167
2345
  }
2168
- const request = prepareRequestOptions$1(resource, clientId);
2169
- // This will always be populated, but let's make TypeScript happy
2170
- if (request.headers) {
2171
- // Remove the Metadata header to invoke a request error from
2172
- // IMDS endpoint
2173
- delete request.headers.Metadata;
2174
- }
2175
- request.spanOptions = (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions;
2176
- request.tracingContext = (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext;
2346
+ const requestOptions = prepareRequestOptions$2(resource, clientId, {
2347
+ skipMetadataHeader: true,
2348
+ skipQuery: true
2349
+ });
2350
+ requestOptions.tracingOptions = options.tracingOptions;
2177
2351
  try {
2178
2352
  // Create a request with a timeout since we expect that
2179
2353
  // not having a "Metadata" header should cause an error to be
2180
2354
  // returned quickly from the endpoint, proving its availability.
2181
- const webResource = identityClient.createWebResource(request);
2182
- // In Kubernetes pods, node-fetch (used by core-http) takes longer than 2 seconds to begin sending the network request,
2183
- // So smaller timeouts will cause this credential to be immediately aborted.
2184
- // This won't be a problem once we move Identity to core-rest-pipeline.
2185
- webResource.timeout = ((_c = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.requestOptions) === null || _c === void 0 ? void 0 : _c.timeout) || 3000;
2355
+ const request = coreRestPipeline.createPipelineRequest(requestOptions);
2356
+ request.timeout = (_b = (_a = options.requestOptions) === null || _a === void 0 ? void 0 : _a.timeout) !== null && _b !== void 0 ? _b : 300;
2357
+ // This MSI uses the imdsEndpoint to get the token, which only uses http://
2358
+ request.allowInsecureConnection = true;
2186
2359
  try {
2187
- await identityClient.sendRequest(webResource);
2360
+ logger$b.info(`${msiName$2}: Pinging the Azure IMDS endpoint`);
2361
+ await identityClient.sendRequest(request);
2188
2362
  }
2189
2363
  catch (err) {
2190
- if ((err.name === "RestError" && err.code === coreHttp.RestError.REQUEST_SEND_ERROR) ||
2364
+ if ((err.name === "RestError" && err.code === coreRestPipeline.RestError.REQUEST_SEND_ERROR) ||
2191
2365
  err.name === "AbortError" ||
2366
+ err.code === "ENETUNREACH" || // Network unreachable
2192
2367
  err.code === "ECONNREFUSED" || // connection refused
2193
2368
  err.code === "EHOSTDOWN" // host is down
2194
2369
  ) {
2195
- // If the request failed, or NodeJS was unable to establish a connection,
2370
+ // If the request failed, or Node.js was unable to establish a connection,
2196
2371
  // or the host was down, we'll assume the IMDS endpoint isn't available.
2197
- logger$a.info(`The Azure IMDS endpoint is unavailable`);
2372
+ logger$b.info(`${msiName$2}: The Azure IMDS endpoint is unavailable`);
2198
2373
  span.setStatus({
2199
2374
  code: coreTracing.SpanStatusCode.ERROR,
2200
2375
  message: err.message
@@ -2203,14 +2378,13 @@ const imdsMsi = {
2203
2378
  }
2204
2379
  }
2205
2380
  // If we received any response, the endpoint is available
2206
- logger$a.info(`The Azure IMDS endpoint is available`);
2207
- // IMDS MSI available!
2381
+ logger$b.info(`${msiName$2}: The Azure IMDS endpoint is available`);
2208
2382
  return true;
2209
2383
  }
2210
2384
  catch (err) {
2211
2385
  // createWebResource failed.
2212
2386
  // This error should bubble up to the user.
2213
- logger$a.info(`Error when creating the WebResource for the IMDS endpoint: ${err.message}`);
2387
+ logger$b.info(`${msiName$2}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
2214
2388
  span.setStatus({
2215
2389
  code: coreTracing.SpanStatusCode.ERROR,
2216
2390
  message: err.message
@@ -2221,88 +2395,58 @@ const imdsMsi = {
2221
2395
  span.end();
2222
2396
  }
2223
2397
  },
2224
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2225
- logger$a.info(`Using the IMDS endpoint coming form 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.`);
2226
2401
  let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
2227
2402
  for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
2228
2403
  try {
2229
- return await msiGenericGetToken(identityClient, prepareRequestOptions$1(resource, clientId), expiresInParser$1, getTokenOptions);
2404
+ return await msiGenericGetToken(identityClient, prepareRequestOptions$2(scopes, clientId), expiresInParser$2, getTokenOptions);
2230
2405
  }
2231
2406
  catch (error) {
2232
2407
  if (error.statusCode === 404) {
2233
- await coreHttp.delay(nextDelayInMs);
2408
+ await coreUtil.delay(nextDelayInMs);
2234
2409
  nextDelayInMs *= imdsMsiRetryConfig.intervalIncrement;
2235
2410
  continue;
2236
2411
  }
2237
2412
  throw error;
2238
2413
  }
2239
2414
  }
2240
- 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.`);
2241
2416
  }
2242
2417
  };
2243
2418
 
2244
2419
  // Copyright (c) Microsoft Corporation.
2245
- const logger$b = credentialLogger("ManagedIdentityCredential - AppServiceMSI 2017");
2246
- function expiresInParser$2(requestBody) {
2247
- // Parse a date format like "06/20/2019 02:57:58 +00:00" and
2248
- // convert it into a JavaScript-formatted date
2249
- return Date.parse(requestBody.expires_on);
2250
- }
2251
- function prepareRequestOptions$2(resource, clientId) {
2252
- const queryParameters = {
2253
- resource,
2254
- "api-version": "2017-09-01"
2255
- };
2256
- if (clientId) {
2257
- queryParameters.clientid = clientId;
2258
- }
2259
- return {
2260
- url: process.env.MSI_ENDPOINT,
2261
- method: "GET",
2262
- queryParameters,
2263
- headers: {
2264
- Accept: "application/json",
2265
- secret: process.env.MSI_SECRET
2266
- }
2267
- };
2268
- }
2269
- const appServiceMsi2017 = {
2270
- async isAvailable() {
2271
- const env = process.env;
2272
- const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
2273
- if (!result) {
2274
- logger$b.info("The Azure App Service MSI 2017 is unavailable.");
2275
- }
2276
- return result;
2277
- },
2278
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2279
- logger$b.info(`Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
2280
- return msiGenericGetToken(identityClient, prepareRequestOptions$2(resource, clientId), expiresInParser$2, getTokenOptions);
2281
- }
2282
- };
2283
-
2284
- // Copyright (c) Microsoft Corporation.
2285
- const logger$c = credentialLogger("ManagedIdentityCredential - ArcMSI");
2420
+ const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
2421
+ const logger$c = credentialLogger(msiName$3);
2286
2422
  // Azure Arc MSI doesn't have a special expiresIn parser.
2287
2423
  const expiresInParser$3 = undefined;
2288
- 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
+ }
2289
2429
  const queryParameters = {
2290
2430
  resource,
2291
2431
  "api-version": azureArcAPIVersion
2292
2432
  };
2293
- return {
2433
+ const query = new URLSearchParams(queryParameters);
2434
+ // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2435
+ if (!process.env.IDENTITY_ENDPOINT) {
2436
+ throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
2437
+ }
2438
+ return coreRestPipeline.createPipelineRequest({
2294
2439
  // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
2295
- url: process.env.IDENTITY_ENDPOINT,
2440
+ url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,
2296
2441
  method: "GET",
2297
- queryParameters,
2298
- headers: {
2442
+ headers: coreRestPipeline.createHttpHeaders({
2299
2443
  Accept: "application/json",
2300
- Metadata: true
2301
- }
2302
- };
2444
+ Metadata: "true"
2445
+ })
2446
+ });
2303
2447
  }
2304
2448
  // Since "fs"'s readFileSync locks the thread, and to avoid extra dependencies.
2305
- function readFileAsync(path, options) {
2449
+ function readFileAsync$1(path, options) {
2306
2450
  return new Promise((resolve, reject) => fs.readFile(path, options, (err, data) => {
2307
2451
  if (err) {
2308
2452
  reject(err);
@@ -2311,43 +2455,207 @@ function readFileAsync(path, options) {
2311
2455
  }));
2312
2456
  }
2313
2457
  async function filePathRequest(identityClient, requestPrepareOptions) {
2314
- const response = await identityClient.sendRequest(identityClient.createWebResource(requestPrepareOptions));
2458
+ const response = await identityClient.sendRequest(coreRestPipeline.createPipelineRequest(requestPrepareOptions));
2315
2459
  if (response.status !== 401) {
2316
2460
  let message = "";
2317
2461
  if (response.bodyAsText) {
2318
2462
  message = ` Response: ${response.bodyAsText}`;
2319
2463
  }
2320
- 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}`);
2321
2465
  }
2322
2466
  const authHeader = response.headers.get("www-authenticate") || "";
2323
- return authHeader.split("=").slice(1)[0];
2467
+ try {
2468
+ return authHeader.split("=").slice(1)[0];
2469
+ }
2470
+ catch (e) {
2471
+ throw Error(`Invalid www-authenticate header format: ${authHeader}`);
2472
+ }
2324
2473
  }
2325
2474
  const arcMsi = {
2326
- 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
+ }
2327
2481
  const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
2328
2482
  if (!result) {
2329
- 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`);
2330
2484
  }
2331
2485
  return result;
2332
2486
  },
2333
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2334
- logger$c.info(`Using the Azure Arc MSI to authenticate.`);
2487
+ async getToken(configuration, getTokenOptions = {}) {
2488
+ var _a;
2489
+ const { identityClient, scopes, clientId } = configuration;
2490
+ logger$c.info(`${msiName$3}: Authenticating.`);
2335
2491
  if (clientId) {
2336
- 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.`);
2337
2493
  }
2338
- 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 });
2339
2495
  const filePath = await filePathRequest(identityClient, requestOptions);
2340
2496
  if (!filePath) {
2341
- throw new Error("Azure Arc MSI failed to find the token file.");
2497
+ throw new Error(`${msiName$3}: Failed to find the token file.`);
2342
2498
  }
2343
- const key = await readFileAsync(filePath, { encoding: "utf-8" });
2344
- requestOptions.headers["Authorization"] = `Basic ${key}`;
2499
+ const key = await readFileAsync$1(filePath, { encoding: "utf-8" });
2500
+ (_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
2345
2501
  return msiGenericGetToken(identityClient, requestOptions, expiresInParser$3, getTokenOptions);
2346
2502
  }
2347
2503
  };
2348
2504
 
2349
2505
  // Copyright (c) Microsoft Corporation.
2350
- 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");
2351
2659
  /**
2352
2660
  * Attempts authentication using a managed identity that has been assigned
2353
2661
  * to the deployment environment. This authentication type works in Azure VMs,
@@ -2374,15 +2682,13 @@ class ManagedIdentityCredential {
2374
2682
  this.identityClient = new IdentityClient(clientIdOrOptions);
2375
2683
  }
2376
2684
  }
2377
- async cachedAvailableMSI(resource, clientId, getTokenOptions) {
2685
+ async cachedAvailableMSI(scopes, clientId, getTokenOptions) {
2378
2686
  if (this.cachedMSI) {
2379
2687
  return this.cachedMSI;
2380
2688
  }
2381
- // "fabricMsi" can't be added yet because our HTTPs pipeline doesn't allow skipping the SSL verification step,
2382
- // which is necessary since Service Fabric only provides self-signed certificates on their Identity Endpoint.
2383
- const MSIs = [appServiceMsi2017, cloudShellMsi, arcMsi, imdsMsi];
2689
+ const MSIs = [fabricMsi, appServiceMsi2017, cloudShellMsi, arcMsi, tokenExchangeMsi(), imdsMsi];
2384
2690
  for (const msi of MSIs) {
2385
- if (await msi.isAvailable(this.identityClient, resource, clientId, getTokenOptions)) {
2691
+ if (await msi.isAvailable(scopes, this.identityClient, clientId, getTokenOptions)) {
2386
2692
  this.cachedMSI = msi;
2387
2693
  return msi;
2388
2694
  }
@@ -2390,12 +2696,15 @@ class ManagedIdentityCredential {
2390
2696
  throw new CredentialUnavailableError("ManagedIdentityCredential - No MSI credential available");
2391
2697
  }
2392
2698
  async authenticateManagedIdentity(scopes, clientId, getTokenOptions) {
2393
- const resource = mapScopesToResource(scopes);
2394
2699
  const { span, updatedOptions } = createSpan("ManagedIdentityCredential-authenticateManagedIdentity", getTokenOptions);
2395
2700
  try {
2396
2701
  // Determining the available MSI, and avoiding checking for other MSIs while the program is running.
2397
- const availableMSI = await this.cachedAvailableMSI(resource, clientId, updatedOptions);
2398
- 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);
2399
2708
  }
2400
2709
  catch (err) {
2401
2710
  span.setStatus({
@@ -2419,7 +2728,7 @@ class ManagedIdentityCredential {
2419
2728
  */
2420
2729
  async getToken(scopes, options) {
2421
2730
  let result = null;
2422
- const { span, updatedOptions } = createSpan("ManagedIdentityCredential-getToken", options);
2731
+ const { span, updatedOptions } = createSpan("ManagedIdentityCredential.getToken", options);
2423
2732
  try {
2424
2733
  // isEndpointAvailable can be true, false, or null,
2425
2734
  // If it's null, it means we don't yet know whether
@@ -2434,7 +2743,7 @@ class ManagedIdentityCredential {
2434
2743
  // It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
2435
2744
  // yet we had no access token. For this reason, we'll throw once with a specific message:
2436
2745
  const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2437
- logger$d.getToken.info(formatError(scopes, error));
2746
+ logger$f.getToken.info(formatError(scopes, error));
2438
2747
  throw error;
2439
2748
  }
2440
2749
  // Since `authenticateManagedIdentity` didn't throw, and the result was not null,
@@ -2446,10 +2755,10 @@ class ManagedIdentityCredential {
2446
2755
  // We've previously determined that the endpoint was unavailable,
2447
2756
  // either because it was unreachable or permanently unable to authenticate.
2448
2757
  const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
2449
- logger$d.getToken.info(formatError(scopes, error));
2758
+ logger$f.getToken.info(formatError(scopes, error));
2450
2759
  throw error;
2451
2760
  }
2452
- logger$d.getToken.info(formatSuccess(scopes));
2761
+ logger$f.getToken.info(formatSuccess(scopes));
2453
2762
  return result;
2454
2763
  }
2455
2764
  catch (err) {
@@ -2470,21 +2779,21 @@ class ManagedIdentityCredential {
2470
2779
  // If either the network is unreachable,
2471
2780
  // we can safely assume the credential is unavailable.
2472
2781
  if (err.code === "ENETUNREACH") {
2473
- const error = new CredentialUnavailableError("ManagedIdentityCredential is unavailable. Network unreachable.");
2474
- 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));
2475
2784
  throw error;
2476
2785
  }
2477
2786
  // If either the host was unreachable,
2478
2787
  // we can safely assume the credential is unavailable.
2479
2788
  if (err.code === "EHOSTUNREACH") {
2480
- const error = new CredentialUnavailableError("ManagedIdentityCredential is unavailable. No managed identity endpoint found.");
2481
- 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));
2482
2791
  throw error;
2483
2792
  }
2484
2793
  // If err.statusCode has a value of 400, it comes from sendTokenRequest,
2485
2794
  // and it means that the endpoint is working, but that no identity is available.
2486
2795
  if (err.statusCode === 400) {
2487
- 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}`);
2488
2797
  }
2489
2798
  // If the error has no status code, we can assume there was no available identity.
2490
2799
  // This will throw silently during any ChainedTokenCredential.
@@ -2532,36 +2841,37 @@ const defaultCredentials = [
2532
2841
  ];
2533
2842
  /**
2534
2843
  * Provides a default {@link ChainedTokenCredential} configuration that should
2535
- * work for most applications that use the Azure SDK. The following credential
2536
- * types will be tried, in order:
2537
- *
2538
- * - {@link EnvironmentCredential}
2539
- * - {@link ManagedIdentityCredential}
2540
- * - {@link VisualStudioCodeCredential}
2541
- * - {@link AzureCliCredential}
2542
- * - {@link AzurePowerShellCredential}
2543
- *
2544
- * Consult the documentation of these credential types for more information
2545
- * on how they attempt authentication.
2546
- *
2547
- * **Note**: `VisualStudioCodeCredential` is provided by an extension package:
2548
- * `@azure/identity-vscode`. If this package is not installed and registered
2549
- * using the extension API (`useIdentityExtension`), then authentication using
2550
- * `VisualStudioCodeCredential` will not be available.
2551
- *
2552
- * Azure Identity extensions may add credential types to the default credential
2553
- * stack.
2844
+ * work for most applications that use the Azure SDK.
2554
2845
  */
2555
2846
  class DefaultAzureCredential extends ChainedTokenCredential {
2556
2847
  /**
2557
2848
  * Creates an instance of the DefaultAzureCredential class.
2558
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
+ *
2559
2869
  * @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.
2560
2870
  */
2561
2871
  constructor(options) {
2562
2872
  super(...defaultCredentials.map((ctor) => new ctor(options)));
2563
2873
  this.UnavailableMessage =
2564
- "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.";
2565
2875
  }
2566
2876
  }
2567
2877
 
@@ -2581,7 +2891,7 @@ const interactiveBrowserMockable = {
2581
2891
  class MsalOpenBrowser extends MsalNode {
2582
2892
  constructor(options) {
2583
2893
  super(options);
2584
- this.logger = credentialLogger("NodeJS MSAL Open Browser");
2894
+ this.logger = credentialLogger("Node.js MSAL Open Browser");
2585
2895
  this.redirectUri = options.redirectUri;
2586
2896
  this.loginHint = options.loginHint;
2587
2897
  const url = new URL(this.redirectUri);
@@ -2709,29 +3019,29 @@ class MsalOpenBrowser extends MsalNode {
2709
3019
  }
2710
3020
 
2711
3021
  // Copyright (c) Microsoft Corporation.
2712
- const logger$e = credentialLogger("InteractiveBrowserCredential");
3022
+ const logger$g = credentialLogger("InteractiveBrowserCredential");
2713
3023
  /**
2714
3024
  * Enables authentication to Azure Active Directory inside of the web browser
2715
3025
  * using the interactive login flow.
2716
- *
2717
- * This credential uses the [Authorization Code Flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow).
2718
- * On NodeJS, it will open a browser window while it listens for a redirect response from the authentication service.
2719
- * 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.
2720
- *
2721
- * 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.
2722
- * 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).
2723
3026
  */
2724
3027
  class InteractiveBrowserCredential {
2725
3028
  /**
2726
3029
  * Creates an instance of InteractiveBrowserCredential with the details needed.
2727
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
+ *
2728
3038
  * @param options - Options for configuring the client which makes the authentication requests.
2729
3039
  */
2730
3040
  constructor(options = {}) {
2731
3041
  const redirectUri = typeof options.redirectUri === "function"
2732
3042
  ? options.redirectUri()
2733
3043
  : options.redirectUri || "http://localhost";
2734
- 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,
2735
3045
  redirectUri }));
2736
3046
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
2737
3047
  }
@@ -2809,7 +3119,7 @@ class MsalDeviceCode extends MsalNode {
2809
3119
  }
2810
3120
 
2811
3121
  // Copyright (c) Microsoft Corporation.
2812
- const logger$f = credentialLogger("DeviceCodeCredential");
3122
+ const logger$h = credentialLogger("DeviceCodeCredential");
2813
3123
  /**
2814
3124
  * Method that logs the user code from the DeviceCodeCredential.
2815
3125
  * @param deviceCodeInfo - The device code.
@@ -2826,10 +3136,24 @@ class DeviceCodeCredential {
2826
3136
  * Creates an instance of DeviceCodeCredential with the details needed
2827
3137
  * to initiate the device code authorization flow with Azure Active Directory.
2828
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
+ *
2829
3153
  * @param options - Options for configuring the client which makes the authentication requests.
2830
3154
  */
2831
3155
  constructor(options) {
2832
- 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 || {} }));
2833
3157
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
2834
3158
  }
2835
3159
  /**
@@ -2870,7 +3194,45 @@ class DeviceCodeCredential {
2870
3194
  }
2871
3195
 
2872
3196
  // Copyright (c) Microsoft Corporation.
2873
- 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");
2874
3236
  /**
2875
3237
  * Enables authentication to Azure Active Directory using an authorization code
2876
3238
  * that was obtained through the authorization code flow, described in more detail
@@ -2884,26 +3246,23 @@ class AuthorizationCodeCredential {
2884
3246
  * @internal
2885
3247
  */
2886
3248
  constructor(tenantId, clientId, clientSecretOrAuthorizationCode, authorizationCodeOrRedirectUri, redirectUriOrOptions, options) {
2887
- this.lastTokenResponse = null;
2888
- checkTenantId(logger$g, tenantId);
2889
- this.clientId = clientId;
2890
- this.tenantId = tenantId;
3249
+ checkTenantId(logger$i, tenantId);
3250
+ let clientSecret = clientSecretOrAuthorizationCode;
2891
3251
  if (typeof redirectUriOrOptions === "string") {
2892
3252
  // the clientId+clientSecret constructor
2893
- this.clientSecret = clientSecretOrAuthorizationCode;
2894
3253
  this.authorizationCode = authorizationCodeOrRedirectUri;
2895
3254
  this.redirectUri = redirectUriOrOptions;
2896
3255
  // options okay
2897
3256
  }
2898
3257
  else {
2899
3258
  // clientId only
2900
- this.clientSecret = undefined;
2901
3259
  this.authorizationCode = clientSecretOrAuthorizationCode;
2902
3260
  this.redirectUri = authorizationCodeOrRedirectUri;
3261
+ clientSecret = undefined;
2903
3262
  options = redirectUriOrOptions;
2904
3263
  }
2905
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
2906
- 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 }));
2907
3266
  }
2908
3267
  /**
2909
3268
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -2913,65 +3272,116 @@ class AuthorizationCodeCredential {
2913
3272
  * @param options - The options used to configure any requests this
2914
3273
  * TokenCredential implementation might make.
2915
3274
  */
2916
- async getToken(scopes, options) {
2917
- var _a, _b;
2918
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
2919
- this.tenantId;
2920
- const { span, updatedOptions } = createSpan("AuthorizationCodeCredential-getToken", options);
2921
- try {
2922
- let tokenResponse = null;
2923
- let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
2924
- if (scopeString.indexOf("offline_access") < 0) {
2925
- scopeString += " offline_access";
2926
- }
2927
- // Try to use the refresh token first
2928
- if (this.lastTokenResponse && this.lastTokenResponse.refreshToken) {
2929
- tokenResponse = await this.identityClient.refreshAccessToken(tenantId, this.clientId, scopeString, this.lastTokenResponse.refreshToken, this.clientSecret, undefined, updatedOptions);
2930
- }
2931
- if (tokenResponse === null) {
2932
- const urlSuffix = getIdentityTokenEndpointSuffix(tenantId);
2933
- const webResource = this.identityClient.createWebResource({
2934
- url: `${this.identityClient.authorityHost}/${tenantId}/${urlSuffix}`,
2935
- method: "POST",
2936
- disableJsonStringifyOnBody: true,
2937
- deserializationMapper: undefined,
2938
- body: qs.stringify({
2939
- client_id: this.clientId,
2940
- grant_type: "authorization_code",
2941
- scope: scopeString,
2942
- code: this.authorizationCode,
2943
- redirect_uri: this.redirectUri,
2944
- client_secret: this.clientSecret
2945
- }),
2946
- headers: {
2947
- Accept: "application/json",
2948
- "Content-Type": "application/x-www-form-urlencoded"
2949
- },
2950
- abortSignal: options && options.abortSignal,
2951
- spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
2952
- tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
2953
- });
2954
- tokenResponse = await this.identityClient.sendTokenRequest(webResource);
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
+ };
2955
3308
  }
2956
- this.lastTokenResponse = tokenResponse;
2957
- logger$g.getToken.info(formatSuccess(scopes));
2958
- const token = tokenResponse && tokenResponse.accessToken;
2959
- if (!token) {
2960
- throw new CredentialUnavailableError("Failed to retrieve a valid token");
3309
+ catch (error) {
3310
+ this.logger.info(formatError("", error));
3311
+ throw error;
2961
3312
  }
2962
- return token;
2963
3313
  }
2964
- catch (err) {
2965
- span.setStatus({
2966
- code: coreTracing.SpanStatusCode.ERROR,
2967
- 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
2968
3326
  });
2969
- logger$g.getToken.info(formatError(scopes, err));
2970
- throw err;
3327
+ return this.handleResult(scopes, this.clientId, result || undefined);
2971
3328
  }
2972
- finally {
2973
- span.end();
3329
+ catch (err) {
3330
+ throw this.handleError(scopes, err, options);
3331
+ }
3332
+ }
3333
+ }
3334
+
3335
+ // Copyright (c) Microsoft Corporation.
3336
+ const credentialName$1 = "OnBehalfOfCredential";
3337
+ const logger$j = credentialLogger(credentialName$1);
3338
+ /**
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).
3340
+ */
3341
+ class OnBehalfOfCredential {
3342
+ /**
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
+ * ```
3360
+ *
3361
+ * @param options - Optional parameters, generally common across credentials.
3362
+ */
3363
+ constructor(options) {
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.`);
2974
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
+ });
2975
3385
  }
2976
3386
  }
2977
3387
 
@@ -3001,11 +3411,12 @@ exports.DeviceCodeCredential = DeviceCodeCredential;
3001
3411
  exports.EnvironmentCredential = EnvironmentCredential;
3002
3412
  exports.InteractiveBrowserCredential = InteractiveBrowserCredential;
3003
3413
  exports.ManagedIdentityCredential = ManagedIdentityCredential;
3414
+ exports.OnBehalfOfCredential = OnBehalfOfCredential;
3004
3415
  exports.UsernamePasswordCredential = UsernamePasswordCredential;
3005
3416
  exports.VisualStudioCodeCredential = VisualStudioCodeCredential;
3006
3417
  exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
3007
3418
  exports.getDefaultAzureCredential = getDefaultAzureCredential;
3008
3419
  exports.logger = logger;
3009
3420
  exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
3010
- exports.useIdentityExtension = useIdentityExtension;
3421
+ exports.useIdentityPlugin = useIdentityPlugin;
3011
3422
  //# sourceMappingURL=index.js.map