@azure/identity 2.0.0-beta.5 → 2.0.0-beta.6

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 (81) hide show
  1. package/CHANGELOG.md +49 -10
  2. package/README.md +26 -21
  3. package/dist/index.js +461 -211
  4. package/dist/index.js.map +1 -1
  5. package/dist-esm/src/client/errors.js +1 -1
  6. package/dist-esm/src/client/errors.js.map +1 -1
  7. package/dist-esm/src/client/identityClient.js +2 -6
  8. package/dist-esm/src/client/identityClient.js.map +1 -1
  9. package/dist-esm/src/credentials/applicationCredential.js +0 -3
  10. package/dist-esm/src/credentials/applicationCredential.js.map +1 -1
  11. package/dist-esm/src/credentials/authorizationCodeCredential.js +12 -76
  12. package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
  13. package/dist-esm/src/credentials/chainedTokenCredential.js +4 -3
  14. package/dist-esm/src/credentials/chainedTokenCredential.js.map +1 -1
  15. package/dist-esm/src/credentials/clientCertificateCredential.js +3 -0
  16. package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
  17. package/dist-esm/src/credentials/clientSecretCredential.browser.js +1 -4
  18. package/dist-esm/src/credentials/clientSecretCredential.browser.js.map +1 -1
  19. package/dist-esm/src/credentials/clientSecretCredential.js +3 -0
  20. package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
  21. package/dist-esm/src/credentials/credentialPersistenceOptions.js.map +1 -1
  22. package/dist-esm/src/credentials/defaultAzureCredential.js +5 -8
  23. package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
  24. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +21 -10
  25. package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
  26. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +23 -12
  27. package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
  28. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +22 -11
  29. package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
  30. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +19 -7
  31. package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
  32. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +29 -20
  33. package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
  34. package/dist-esm/src/credentials/managedIdentityCredential/index.js +13 -10
  35. package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
  36. package/dist-esm/src/credentials/managedIdentityCredential/models.js.map +1 -1
  37. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +82 -0
  38. package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -0
  39. package/dist-esm/src/credentials/managedIdentityCredential/utils.js +10 -5
  40. package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
  41. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js +17 -0
  42. package/dist-esm/src/credentials/onBehalfOfCredential.browser.js.map +1 -0
  43. package/dist-esm/src/credentials/onBehalfOfCredential.js +62 -0
  44. package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -0
  45. package/dist-esm/src/credentials/{visualStudioCodeCredentialExtension.js → onBehalfOfCredentialOptions.js} +1 -1
  46. package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -0
  47. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js +10 -13
  48. package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
  49. package/dist-esm/src/credentials/usernamePasswordCredential.js +3 -0
  50. package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
  51. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js +1 -1
  52. package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js.map +1 -1
  53. package/dist-esm/src/credentials/visualStudioCodeCredential.js +11 -1
  54. package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
  55. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js +4 -0
  56. package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js.map +1 -0
  57. package/dist-esm/src/index.js +2 -1
  58. package/dist-esm/src/index.js.map +1 -1
  59. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +41 -0
  60. package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -0
  61. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +48 -29
  62. package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
  63. package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
  64. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +56 -0
  65. package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -0
  66. package/dist-esm/src/msal/nodeFlows/nodeCommon.js +6 -1
  67. package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +1 -1
  68. package/dist-esm/src/msal/nodeFlows/tokenCachePersistenceOptions.js.map +1 -1
  69. package/dist-esm/src/plugins/consumer.browser.js +7 -0
  70. package/dist-esm/src/plugins/consumer.browser.js.map +1 -0
  71. package/dist-esm/src/{extensions → plugins}/consumer.js +12 -12
  72. package/dist-esm/src/plugins/consumer.js.map +1 -0
  73. package/dist-esm/src/{extensions → plugins}/provider.js +0 -0
  74. package/dist-esm/src/plugins/provider.js.map +1 -0
  75. package/package.json +10 -12
  76. package/types/identity.d.ts +126 -41
  77. package/dist-esm/src/credentials/visualStudioCodeCredentialExtension.js.map +0 -1
  78. package/dist-esm/src/extensions/consumer.browser.js +0 -7
  79. package/dist-esm/src/extensions/consumer.browser.js.map +0 -1
  80. package/dist-esm/src/extensions/consumer.js.map +0 -1
  81. package/dist-esm/src/extensions/provider.js.map +0 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ var coreTracing = require('@azure/core-tracing');
10
10
  var coreUtil = require('@azure/core-util');
11
11
  var coreRestPipeline = require('@azure/core-rest-pipeline');
12
12
  var abortController = require('@azure/abort-controller');
13
- var logger$h = require('@azure/logger');
13
+ var logger$j = require('@azure/logger');
14
14
  var msalCommon = require('@azure/msal-common');
15
15
  var uuid = require('uuid');
16
16
  var fs = require('fs');
@@ -19,7 +19,7 @@ var os = _interopDefault(require('os'));
19
19
  var path = _interopDefault(require('path'));
20
20
  var child_process = require('child_process');
21
21
  var crypto = require('crypto');
22
- var qs = _interopDefault(require('qs'));
22
+ var util = require('util');
23
23
  var http = _interopDefault(require('http'));
24
24
  var open = _interopDefault(require('open'));
25
25
  var stoppable = _interopDefault(require('stoppable'));
@@ -149,7 +149,7 @@ const AggregateAuthenticationErrorName = "AggregateAuthenticationError";
149
149
  class AggregateAuthenticationError extends Error {
150
150
  constructor(errors, errorMessage) {
151
151
  const errorDetail = errors.join("\n");
152
- super(`${errorMessage}\n\n${errorDetail}`);
152
+ super(`${errorMessage}\n${errorDetail}`);
153
153
  this.errors = errors;
154
154
  // Ensure that this type reports the correct name
155
155
  this.name = AggregateAuthenticationErrorName;
@@ -224,7 +224,7 @@ async function trace(operationName, options, fn, createSpanFn = createSpan) {
224
224
  /**
225
225
  * The AzureLogger used for all clients within the identity package
226
226
  */
227
- const logger = logger$h.createClientLogger("identity");
227
+ const logger = logger$j.createClientLogger("identity");
228
228
  /**
229
229
  * Separates a list of environment variable names into a plain object with two arrays: an array of missing environment variables and another array with assigned environment variables.
230
230
  * @param supportedEnvVars - List of environment variable names
@@ -315,7 +315,7 @@ function getIdentityClientAuthorityHost(options) {
315
315
  class IdentityClient extends coreClient.ServiceClient {
316
316
  constructor(options) {
317
317
  var _a;
318
- const packageDetails = `azsdk-js-identity/2.0.0-beta.5`;
318
+ const packageDetails = `azsdk-js-identity/2.0.0-beta.6`;
319
319
  const userAgentPrefix = ((_a = options === null || options === void 0 ? void 0 : options.userAgentOptions) === null || _a === void 0 ? void 0 : _a.userAgentPrefix)
320
320
  ? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
321
321
  : `${packageDetails}`;
@@ -359,7 +359,6 @@ class IdentityClient extends coreClient.ServiceClient {
359
359
  }
360
360
  }
361
361
  async refreshAccessToken(tenantId, clientId, scopes, refreshToken, clientSecret, expiresOnParser, options) {
362
- var _a, _b;
363
362
  if (refreshToken === undefined) {
364
363
  return null;
365
364
  }
@@ -386,10 +385,7 @@ class IdentityClient extends coreClient.ServiceClient {
386
385
  Accept: "application/json",
387
386
  "Content-Type": "application/x-www-form-urlencoded"
388
387
  }),
389
- tracingOptions: {
390
- spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
391
- tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
392
- }
388
+ tracingOptions: updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions
393
389
  });
394
390
  const response = await this.sendTokenRequest(request, expiresOnParser);
395
391
  logger.info(`IdentityClient: refreshed token for client ID: ${clientId}`);
@@ -913,7 +909,12 @@ class MsalNode extends MsalBaseUtilities {
913
909
  this.createCachePlugin = () => persistenceProvider(options.tokenCachePersistenceOptions);
914
910
  }
915
911
  else if ((_b = options.tokenCachePersistenceOptions) === null || _b === void 0 ? void 0 : _b.enabled) {
916
- throw new Error("Persistent token caching was requested, but no persistence provider was configured (do you need to use the `@azure/identity-cache-persistence` package?)");
912
+ throw new Error([
913
+ "Persistent token caching was requested, but no persistence provider was configured.",
914
+ "You must install the identity-cache-persistence plugin package (`npm install --save @azure/identity-cache-persistence`)",
915
+ "and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
916
+ "`useIdentityPlugin(cachePersistencePlugin)` before using `tokenCachePersistenceOptions`."
917
+ ].join(" "));
917
918
  }
918
919
  this.azureRegion = (_c = options.regionalAuthority) !== null && _c !== void 0 ? _c : process.env.AZURE_REGIONAL_AUTHORITY_NAME;
919
920
  if (this.azureRegion === exports.RegionalAuthority.AutoDiscoverRegion) {
@@ -1145,6 +1146,11 @@ class VisualStudioCodeCredential {
1145
1146
  /**
1146
1147
  * Creates an instance of VisualStudioCodeCredential to use for automatically authenticating via VSCode.
1147
1148
  *
1149
+ * **Note**: `VisualStudioCodeCredential` is provided by a plugin package:
1150
+ * `@azure/identity-vscode`. If this package is not installed and registered
1151
+ * using the plugin API (`useIdentityPlugin`), then authentication using
1152
+ * `VisualStudioCodeCredential` will not be available.
1153
+ *
1148
1154
  * @param options - Options for configuring the client which makes the authentication request.
1149
1155
  */
1150
1156
  constructor(options) {
@@ -1198,7 +1204,12 @@ class VisualStudioCodeCredential {
1198
1204
  const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
1199
1205
  this.tenantId;
1200
1206
  if (findCredentials === undefined) {
1201
- throw new CredentialUnavailableError("No implementation of VisualStudioCodeCredential is available (do you need to install and use the `@azure/identity-vscode` extension package?)");
1207
+ throw new CredentialUnavailableError([
1208
+ "No implementation of `VisualStudioCodeCredential` is available.",
1209
+ "You must install the identity-vscode plugin package (`npm install --save-dev @azure/identity-vscode`)",
1210
+ "and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling",
1211
+ "`useIdentityPlugin(vsCodePlugin)` before creating a `VisualStudioCodeCredential`."
1212
+ ].join(" "));
1202
1213
  }
1203
1214
  let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
1204
1215
  // Check to make sure the scope we get back is a valid scope
@@ -1243,17 +1254,17 @@ class VisualStudioCodeCredential {
1243
1254
 
1244
1255
  // Copyright (c) Microsoft Corporation.
1245
1256
  /**
1246
- * The context passed to an Identity Extension. This contains objects that
1247
- * extensions can use to set backend implementations.
1257
+ * The context passed to an Identity plugin. This contains objects that
1258
+ * plugins can use to set backend implementations.
1248
1259
  * @internal
1249
1260
  */
1250
- const extensionContext = {
1261
+ const pluginContext = {
1251
1262
  cachePluginControl: msalNodeFlowCacheControl,
1252
1263
  vsCodeCredentialControl: vsCodeCredentialControl
1253
1264
  };
1254
1265
  /**
1255
- * Extend Azure Identity with additional functionality. Pass an extension from
1256
- * an extension package, such as:
1266
+ * Extend Azure Identity with additional functionality. Pass a plugin from
1267
+ * a plugin package, such as:
1257
1268
  *
1258
1269
  * - `@azure/identity-cache-persistence`: provides persistent token caching
1259
1270
  * - `@azure/identity-vscode`: provides the dependencies of
@@ -1262,12 +1273,12 @@ const extensionContext = {
1262
1273
  * Example:
1263
1274
  *
1264
1275
  * ```javascript
1265
- * import { cachePersistenceExtension } from "@azure/identity-cache-persistence";
1276
+ * import { cachePersistencePlugin } from "@azure/identity-cache-persistence";
1266
1277
  *
1267
- * import { useIdentityExtension, DefaultAzureCredential } from "@azure/identity";
1268
- * useIdentityExtension(persistence);
1278
+ * import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
1279
+ * useIdentityPlugin(cachePersistencePlugin);
1269
1280
  *
1270
- * // The extension has the capability to extend `DefaultAzureCredential` and to
1281
+ * // The plugin has the capability to extend `DefaultAzureCredential` and to
1271
1282
  * // add middleware to the underlying credentials, such as persistence.
1272
1283
  * const credential = new DefaultAzureCredential({
1273
1284
  * tokenCachePersistenceOptions: {
@@ -1276,10 +1287,10 @@ const extensionContext = {
1276
1287
  * });
1277
1288
  * ```
1278
1289
  *
1279
- * @param extension - the extension to register
1290
+ * @param plugin - the plugin to register
1280
1291
  */
1281
- function useIdentityExtension(extension) {
1282
- extension(extensionContext);
1292
+ function useIdentityPlugin(plugin) {
1293
+ plugin(pluginContext);
1283
1294
  }
1284
1295
 
1285
1296
  // Copyright (c) Microsoft Corporation.
@@ -1327,12 +1338,13 @@ class ChainedTokenCredential {
1327
1338
  */
1328
1339
  async getToken(scopes, options) {
1329
1340
  let token = null;
1341
+ let successfulCredentialName = "";
1330
1342
  const errors = [];
1331
1343
  const { span, updatedOptions } = createSpan("ChainedTokenCredential-getToken", options);
1332
1344
  for (let i = 0; i < this._sources.length && token === null; i++) {
1333
1345
  try {
1334
1346
  token = await this._sources[i].getToken(scopes, updatedOptions);
1335
- this.selectedCredential = this._sources[i];
1347
+ successfulCredentialName = this._sources[i].constructor.name;
1336
1348
  }
1337
1349
  catch (err) {
1338
1350
  if (err.name === "CredentialUnavailableError" ||
@@ -1346,7 +1358,7 @@ class ChainedTokenCredential {
1346
1358
  }
1347
1359
  }
1348
1360
  if (!token && errors.length > 0) {
1349
- const err = new AggregateAuthenticationError(errors);
1361
+ const err = new AggregateAuthenticationError(errors, "ChainedTokenCredential authentication failed.");
1350
1362
  span.setStatus({
1351
1363
  code: coreTracing.SpanStatusCode.ERROR,
1352
1364
  message: err.message
@@ -1355,7 +1367,7 @@ class ChainedTokenCredential {
1355
1367
  throw err;
1356
1368
  }
1357
1369
  span.end();
1358
- logger$2.getToken.info(`Result for ${this.selectedCredential.constructor.name}: ${formatSuccess(scopes)}`);
1370
+ logger$2.getToken.info(`Result for ${successfulCredentialName}: ${formatSuccess(scopes)}`);
1359
1371
  if (token === null) {
1360
1372
  throw new CredentialUnavailableError("Failed to retrieve a valid token");
1361
1373
  }
@@ -1759,6 +1771,9 @@ class ClientSecretCredential {
1759
1771
  * @param options - Options for configuring the client which makes the authentication request.
1760
1772
  */
1761
1773
  constructor(tenantId, clientId, clientSecret, options = {}) {
1774
+ if (!tenantId || !clientId || !clientSecret) {
1775
+ throw new Error("ClientSecretCredential: tenantId, clientId, and clientSecret are required parameters.");
1776
+ }
1762
1777
  this.msalFlow = new MsalClientSecret(Object.assign(Object.assign({}, options), { logger: logger$5,
1763
1778
  clientId,
1764
1779
  tenantId,
@@ -1781,6 +1796,40 @@ class ClientSecretCredential {
1781
1796
  }
1782
1797
 
1783
1798
  // Copyright (c) Microsoft Corporation.
1799
+ const readFileAsync = util.promisify(fs.readFile);
1800
+ /**
1801
+ * Tries to asynchronously load a certificate from the given path.
1802
+ *
1803
+ * @param certificatePath - Path to the certificate.
1804
+ * @param sendCertificateChain - Option to include x5c header for SubjectName and Issuer name authorization.
1805
+ * @returns - The certificate parts, or `undefined` if the certificate could not be loaded.
1806
+ * @internal
1807
+ */
1808
+ async function parseCertificate(certificatePath, sendCertificateChain) {
1809
+ const certificateParts = {};
1810
+ certificateParts.certificateContents = await readFileAsync(certificatePath, "utf8");
1811
+ if (sendCertificateChain) {
1812
+ certificateParts.x5c = certificateParts.certificateContents;
1813
+ }
1814
+ const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
1815
+ const publicKeys = [];
1816
+ // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
1817
+ let match;
1818
+ do {
1819
+ match = certificatePattern.exec(certificateParts.certificateContents);
1820
+ if (match) {
1821
+ publicKeys.push(match[3]);
1822
+ }
1823
+ } while (match);
1824
+ if (publicKeys.length === 0) {
1825
+ throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
1826
+ }
1827
+ certificateParts.thumbprint = crypto.createHash("sha1")
1828
+ .update(Buffer.from(publicKeys[0], "base64"))
1829
+ .digest("hex")
1830
+ .toUpperCase();
1831
+ return certificateParts;
1832
+ }
1784
1833
  /**
1785
1834
  * MSAL client certificate client. Calls to MSAL's confidential application's `acquireTokenByClientCredential` during `doGetToken`.
1786
1835
  * @internal
@@ -1789,40 +1838,24 @@ class MsalClientCertificate extends MsalNode {
1789
1838
  constructor(options) {
1790
1839
  super(options);
1791
1840
  this.requiresConfidential = true;
1841
+ this.certificatePath = options.certificatePath;
1792
1842
  this.sendCertificateChain = options.sendCertificateChain;
1793
- const parts = this.parseCertificate(options.certificatePath);
1794
- this.msalConfig.auth.clientCertificate = {
1795
- thumbprint: parts.thumbprint,
1796
- privateKey: parts.certificateContents,
1797
- x5c: parts.x5c
1798
- };
1799
1843
  }
1800
- parseCertificate(certificatePath) {
1801
- const certificateParts = {};
1802
- certificateParts.certificateContents = fs.readFileSync(certificatePath, "utf8");
1803
- if (this.sendCertificateChain) {
1804
- certificateParts.x5c = certificateParts.certificateContents;
1805
- }
1806
- const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
1807
- const publicKeys = [];
1808
- // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
1809
- let match;
1810
- do {
1811
- match = certificatePattern.exec(certificateParts.certificateContents);
1812
- if (match) {
1813
- publicKeys.push(match[3]);
1814
- }
1815
- } while (match);
1816
- if (publicKeys.length === 0) {
1817
- const error = new Error("The file at the specified path does not contain a PEM-encoded certificate.");
1844
+ // Changing the MSAL configuration asynchronously
1845
+ async init(options) {
1846
+ try {
1847
+ const parts = await parseCertificate(this.certificatePath, this.sendCertificateChain);
1848
+ this.msalConfig.auth.clientCertificate = {
1849
+ thumbprint: parts.thumbprint,
1850
+ privateKey: parts.certificateContents,
1851
+ x5c: parts.x5c
1852
+ };
1853
+ }
1854
+ catch (error) {
1818
1855
  this.logger.info(formatError("", error));
1819
1856
  throw error;
1820
1857
  }
1821
- certificateParts.thumbprint = crypto.createHash("sha1")
1822
- .update(Buffer.from(publicKeys[0], "base64"))
1823
- .digest("hex")
1824
- .toUpperCase();
1825
- return certificateParts;
1858
+ return super.init(options);
1826
1859
  }
1827
1860
  async doGetToken(scopes, options = {}) {
1828
1861
  try {
@@ -1864,6 +1897,9 @@ class ClientCertificateCredential {
1864
1897
  * @param options - Options for configuring the client which makes the authentication request.
1865
1898
  */
1866
1899
  constructor(tenantId, clientId, certificatePath, options = {}) {
1900
+ if (!tenantId || !clientId || !certificatePath) {
1901
+ throw new Error("ClientCertificateCredential: tenantId, clientId, and certificatePath are required parameters.");
1902
+ }
1867
1903
  this.msalFlow = new MsalClientCertificate(Object.assign(Object.assign({}, options), { certificatePath,
1868
1904
  logger: logger$6,
1869
1905
  clientId,
@@ -1937,6 +1973,9 @@ class UsernamePasswordCredential {
1937
1973
  * @param options - Options for configuring the client which makes the authentication request.
1938
1974
  */
1939
1975
  constructor(tenantId, clientId, username, password, options = {}) {
1976
+ if (!tenantId || !clientId || !username || !password) {
1977
+ throw new Error("UsernamePasswordCredential: tenantId, clientId, username and password are required parameters.");
1978
+ }
1940
1979
  this.msalFlow = new MsalUsernamePassword(Object.assign(Object.assign({}, options), { logger: logger$7,
1941
1980
  clientId,
1942
1981
  tenantId,
@@ -2088,11 +2127,19 @@ const imdsApiVersion = "2018-02-01";
2088
2127
  const azureArcAPIVersion = "2019-11-01";
2089
2128
 
2090
2129
  // Copyright (c) Microsoft Corporation.
2130
+ /**
2131
+ * Most MSIs send requests to the IMDS endpoint, or a similar endpoint. These are GET requests that require sending a `resource` parameter on the query.
2132
+ * This resource can be derived from the scopes received through the getToken call, as long as only one scope is received.
2133
+ * Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case.
2134
+ *
2135
+ * For that reason, when we encounter multiple scopes, we return undefined.
2136
+ * It's up to the individual MSI implementations to throw the errors (which helps us provide less generic errors).
2137
+ */
2091
2138
  function mapScopesToResource(scopes) {
2092
2139
  let scope = "";
2093
2140
  if (Array.isArray(scopes)) {
2094
2141
  if (scopes.length !== 1) {
2095
- throw new Error("To convert to a resource string the specified array must be exactly length 1");
2142
+ return;
2096
2143
  }
2097
2144
  scope = scopes[0];
2098
2145
  }
@@ -2105,22 +2152,24 @@ function mapScopesToResource(scopes) {
2105
2152
  return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
2106
2153
  }
2107
2154
  async function msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions = {}) {
2108
- const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal, tracingOptions: {
2109
- spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions,
2110
- tracingContext: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.tracingContext
2111
- } }, requestOptions), { allowInsecureConnection: true }));
2155
+ const request = coreRestPipeline.createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, requestOptions), { allowInsecureConnection: true }));
2112
2156
  const tokenResponse = await identityClient.sendTokenRequest(request, expiresInParser);
2113
2157
  return (tokenResponse && tokenResponse.accessToken) || null;
2114
2158
  }
2115
2159
 
2116
2160
  // Copyright (c) Microsoft Corporation.
2117
- const logger$9 = credentialLogger("ManagedIdentityCredential - AppServiceMSI 2017");
2161
+ const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
2162
+ const logger$9 = credentialLogger(msiName);
2118
2163
  function expiresInParser(requestBody) {
2119
2164
  // Parse a date format like "06/20/2019 02:57:58 +00:00" and
2120
2165
  // convert it into a JavaScript-formatted date
2121
2166
  return Date.parse(requestBody.expires_on);
2122
2167
  }
2123
- function prepareRequestOptions(resource, clientId) {
2168
+ function prepareRequestOptions(scopes, clientId) {
2169
+ const resource = mapScopesToResource(scopes);
2170
+ if (!resource) {
2171
+ throw new Error(`${msiName}: Multiple scopes are not supported.`);
2172
+ }
2124
2173
  const queryParameters = {
2125
2174
  resource,
2126
2175
  "api-version": "2017-09-01"
@@ -2131,10 +2180,10 @@ function prepareRequestOptions(resource, clientId) {
2131
2180
  const query = new URLSearchParams(queryParameters);
2132
2181
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2133
2182
  if (!process.env.MSI_ENDPOINT) {
2134
- throw new Error("Missing environment variable: MSI_ENDPOINT");
2183
+ throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
2135
2184
  }
2136
2185
  if (!process.env.MSI_SECRET) {
2137
- throw new Error("Missing environment variable: MSI_SECRET");
2186
+ throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
2138
2187
  }
2139
2188
  return {
2140
2189
  url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
@@ -2146,25 +2195,36 @@ function prepareRequestOptions(resource, clientId) {
2146
2195
  };
2147
2196
  }
2148
2197
  const appServiceMsi2017 = {
2149
- async isAvailable() {
2198
+ async isAvailable(scopes) {
2199
+ const resource = mapScopesToResource(scopes);
2200
+ if (!resource) {
2201
+ logger$9.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
2202
+ return false;
2203
+ }
2150
2204
  const env = process.env;
2151
2205
  const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
2152
2206
  if (!result) {
2153
- logger$9.info("The Azure App Service MSI 2017 is unavailable.");
2207
+ logger$9.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
2154
2208
  }
2155
2209
  return result;
2156
2210
  },
2157
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2158
- logger$9.info(`Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
2159
- return msiGenericGetToken(identityClient, prepareRequestOptions(resource, clientId), expiresInParser, getTokenOptions);
2211
+ async getToken(configuration, getTokenOptions = {}) {
2212
+ const { identityClient, scopes, clientId } = configuration;
2213
+ 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].`);
2214
+ return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
2160
2215
  }
2161
2216
  };
2162
2217
 
2163
2218
  // Copyright (c) Microsoft Corporation.
2164
- const logger$a = credentialLogger("ManagedIdentityCredential - CloudShellMSI");
2219
+ const msiName$1 = "ManagedIdentityCredential - CloudShellMSI";
2220
+ const logger$a = credentialLogger(msiName$1);
2165
2221
  // Cloud Shell MSI doesn't have a special expiresIn parser.
2166
2222
  const expiresInParser$1 = undefined;
2167
- function prepareRequestOptions$1(resource, clientId) {
2223
+ function prepareRequestOptions$1(scopes, clientId) {
2224
+ const resource = mapScopesToResource(scopes);
2225
+ if (!resource) {
2226
+ throw new Error(`${msiName$1}: Multiple scopes are not supported.`);
2227
+ }
2168
2228
  const body = {
2169
2229
  resource
2170
2230
  };
@@ -2173,12 +2233,13 @@ function prepareRequestOptions$1(resource, clientId) {
2173
2233
  }
2174
2234
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2175
2235
  if (!process.env.MSI_ENDPOINT) {
2176
- throw new Error("Missing environment variable: MSI_ENDPOINT");
2236
+ throw new Error(`${msiName$1}: Missing environment variable: MSI_ENDPOINT`);
2177
2237
  }
2238
+ const params = new URLSearchParams(body);
2178
2239
  return {
2179
2240
  url: process.env.MSI_ENDPOINT,
2180
2241
  method: "POST",
2181
- body: qs.stringify(body),
2242
+ body: params.toString(),
2182
2243
  headers: coreRestPipeline.createHttpHeaders({
2183
2244
  Accept: "application/json",
2184
2245
  Metadata: "true",
@@ -2187,37 +2248,48 @@ function prepareRequestOptions$1(resource, clientId) {
2187
2248
  };
2188
2249
  }
2189
2250
  const cloudShellMsi = {
2190
- async isAvailable() {
2251
+ async isAvailable(scopes) {
2252
+ const resource = mapScopesToResource(scopes);
2253
+ if (!resource) {
2254
+ logger$a.info(`${msiName$1}: Unavailable. Multiple scopes are not supported.`);
2255
+ return false;
2256
+ }
2191
2257
  const result = Boolean(process.env.MSI_ENDPOINT);
2192
2258
  if (!result) {
2193
- logger$a.info("The Azure Cloud Shell MSI is unavailable.");
2259
+ logger$a.info(`${msiName$1}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
2194
2260
  }
2195
2261
  return result;
2196
2262
  },
2197
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2198
- logger$a.info(`Using the endpoint coming form the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the Cloud Shell to proceed with the authentication.`);
2199
- return msiGenericGetToken(identityClient, prepareRequestOptions$1(resource, clientId), expiresInParser$1, getTokenOptions);
2263
+ async getToken(configuration, getTokenOptions = {}) {
2264
+ const { identityClient, scopes, clientId } = configuration;
2265
+ logger$a.info(`${msiName$1}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
2266
+ return msiGenericGetToken(identityClient, prepareRequestOptions$1(scopes, clientId), expiresInParser$1, getTokenOptions);
2200
2267
  }
2201
2268
  };
2202
2269
 
2203
2270
  // Copyright (c) Microsoft Corporation.
2204
- const logger$b = credentialLogger("ManagedIdentityCredential - IMDS");
2271
+ const msiName$2 = "ManagedIdentityCredential - IMDS";
2272
+ const logger$b = credentialLogger(msiName$2);
2205
2273
  function expiresInParser$2(requestBody) {
2206
2274
  if (requestBody.expires_on) {
2207
2275
  // Use the expires_on timestamp if it's available
2208
2276
  const expires = +requestBody.expires_on * 1000;
2209
- logger$b.info(`IMDS using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
2277
+ logger$b.info(`${msiName$2}: IMDS using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
2210
2278
  return expires;
2211
2279
  }
2212
2280
  else {
2213
2281
  // If these aren't possible, use expires_in and calculate a timestamp
2214
2282
  const expires = Date.now() + requestBody.expires_in * 1000;
2215
- logger$b.info(`IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
2283
+ logger$b.info(`${msiName$2}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
2216
2284
  return expires;
2217
2285
  }
2218
2286
  }
2219
- function prepareRequestOptions$2(resource, clientId) {
2287
+ function prepareRequestOptions$2(scopes, clientId) {
2220
2288
  var _a;
2289
+ const resource = mapScopesToResource(scopes);
2290
+ if (!resource) {
2291
+ throw new Error(`${msiName$2}: Multiple scopes are not supported.`);
2292
+ }
2221
2293
  const queryParameters = {
2222
2294
  resource,
2223
2295
  "api-version": imdsApiVersion
@@ -2225,7 +2297,8 @@ function prepareRequestOptions$2(resource, clientId) {
2225
2297
  if (clientId) {
2226
2298
  queryParameters.client_id = clientId;
2227
2299
  }
2228
- const query = qs.stringify(queryParameters);
2300
+ const params = new URLSearchParams(queryParameters);
2301
+ const query = params.toString();
2229
2302
  const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
2230
2303
  return {
2231
2304
  url: `${url}?${query}`,
@@ -2243,8 +2316,13 @@ const imdsMsiRetryConfig = {
2243
2316
  intervalIncrement: 2
2244
2317
  };
2245
2318
  const imdsMsi = {
2246
- async isAvailable(identityClient, resource, clientId, getTokenOptions) {
2319
+ async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
2247
2320
  var _a, _b;
2321
+ const resource = mapScopesToResource(scopes);
2322
+ if (!resource) {
2323
+ logger$b.info(`${msiName$2}: Unavailable. Multiple scopes are not supported.`);
2324
+ return false;
2325
+ }
2248
2326
  const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
2249
2327
  // if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
2250
2328
  if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
@@ -2257,10 +2335,7 @@ const imdsMsi = {
2257
2335
  // IMDS endpoint
2258
2336
  requestOptions.headers.delete("Metadata");
2259
2337
  }
2260
- requestOptions.tracingOptions = {
2261
- spanOptions: options.tracingOptions && options.tracingOptions.spanOptions,
2262
- tracingContext: options.tracingOptions && options.tracingOptions.tracingContext
2263
- };
2338
+ requestOptions.tracingOptions = options.tracingOptions;
2264
2339
  try {
2265
2340
  // Create a request with a timeout since we expect that
2266
2341
  // not having a "Metadata" header should cause an error to be
@@ -2270,18 +2345,19 @@ const imdsMsi = {
2270
2345
  // This MSI uses the imdsEndpoint to get the token, which only uses http://
2271
2346
  request.allowInsecureConnection = true;
2272
2347
  try {
2273
- logger$b.info(`Pinging the Azure IMDS endpoint`);
2348
+ logger$b.info(`${msiName$2}: Pinging the Azure IMDS endpoint`);
2274
2349
  await identityClient.sendRequest(request);
2275
2350
  }
2276
2351
  catch (err) {
2277
2352
  if ((err.name === "RestError" && err.code === coreRestPipeline.RestError.REQUEST_SEND_ERROR) ||
2278
2353
  err.name === "AbortError" ||
2354
+ err.code === "ENETUNREACH" || // Network unreachable
2279
2355
  err.code === "ECONNREFUSED" || // connection refused
2280
2356
  err.code === "EHOSTDOWN" // host is down
2281
2357
  ) {
2282
2358
  // If the request failed, or Node.js was unable to establish a connection,
2283
2359
  // or the host was down, we'll assume the IMDS endpoint isn't available.
2284
- logger$b.info(`The Azure IMDS endpoint is unavailable`);
2360
+ logger$b.info(`${msiName$2}: The Azure IMDS endpoint is unavailable`);
2285
2361
  span.setStatus({
2286
2362
  code: coreTracing.SpanStatusCode.ERROR,
2287
2363
  message: err.message
@@ -2290,13 +2366,13 @@ const imdsMsi = {
2290
2366
  }
2291
2367
  }
2292
2368
  // If we received any response, the endpoint is available
2293
- logger$b.info(`The Azure IMDS endpoint is available`);
2369
+ logger$b.info(`${msiName$2}: The Azure IMDS endpoint is available`);
2294
2370
  return true;
2295
2371
  }
2296
2372
  catch (err) {
2297
2373
  // createWebResource failed.
2298
2374
  // This error should bubble up to the user.
2299
- logger$b.info(`Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
2375
+ logger$b.info(`${msiName$2}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
2300
2376
  span.setStatus({
2301
2377
  code: coreTracing.SpanStatusCode.ERROR,
2302
2378
  message: err.message
@@ -2307,12 +2383,13 @@ const imdsMsi = {
2307
2383
  span.end();
2308
2384
  }
2309
2385
  },
2310
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2311
- logger$b.info(`Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
2386
+ async getToken(configuration, getTokenOptions = {}) {
2387
+ const { identityClient, scopes, clientId } = configuration;
2388
+ logger$b.info(`${msiName$2}: Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
2312
2389
  let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
2313
2390
  for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
2314
2391
  try {
2315
- return await msiGenericGetToken(identityClient, prepareRequestOptions$2(resource, clientId), expiresInParser$2, getTokenOptions);
2392
+ return await msiGenericGetToken(identityClient, prepareRequestOptions$2(scopes, clientId), expiresInParser$2, getTokenOptions);
2316
2393
  }
2317
2394
  catch (error) {
2318
2395
  if (error.statusCode === 404) {
@@ -2323,15 +2400,20 @@ const imdsMsi = {
2323
2400
  throw error;
2324
2401
  }
2325
2402
  }
2326
- throw new AuthenticationError(404, `Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
2403
+ throw new AuthenticationError(404, `${msiName$2}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
2327
2404
  }
2328
2405
  };
2329
2406
 
2330
2407
  // Copyright (c) Microsoft Corporation.
2331
- const logger$c = credentialLogger("ManagedIdentityCredential - ArcMSI");
2408
+ const msiName$3 = "ManagedIdentityCredential - Azure Arc MSI";
2409
+ const logger$c = credentialLogger(msiName$3);
2332
2410
  // Azure Arc MSI doesn't have a special expiresIn parser.
2333
2411
  const expiresInParser$3 = undefined;
2334
- function prepareRequestOptions$3(resource) {
2412
+ function prepareRequestOptions$3(scopes) {
2413
+ const resource = mapScopesToResource(scopes);
2414
+ if (!resource) {
2415
+ throw new Error(`${msiName$3}: Multiple scopes are not supported.`);
2416
+ }
2335
2417
  const queryParameters = {
2336
2418
  resource,
2337
2419
  "api-version": azureArcAPIVersion
@@ -2339,7 +2421,7 @@ function prepareRequestOptions$3(resource) {
2339
2421
  const query = new URLSearchParams(queryParameters);
2340
2422
  // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
2341
2423
  if (!process.env.IDENTITY_ENDPOINT) {
2342
- throw new Error("Missing environment variable: IDENTITY_ENDPOINT");
2424
+ throw new Error(`${msiName$3}: Missing environment variable: IDENTITY_ENDPOINT`);
2343
2425
  }
2344
2426
  return coreRestPipeline.createPipelineRequest({
2345
2427
  // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
@@ -2352,7 +2434,7 @@ function prepareRequestOptions$3(resource) {
2352
2434
  });
2353
2435
  }
2354
2436
  // Since "fs"'s readFileSync locks the thread, and to avoid extra dependencies.
2355
- function readFileAsync(path, options) {
2437
+ function readFileAsync$1(path, options) {
2356
2438
  return new Promise((resolve, reject) => fs.readFile(path, options, (err, data) => {
2357
2439
  if (err) {
2358
2440
  reject(err);
@@ -2367,7 +2449,7 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
2367
2449
  if (response.bodyAsText) {
2368
2450
  message = ` Response: ${response.bodyAsText}`;
2369
2451
  }
2370
- throw new AuthenticationError(response.status, `To authenticate with Azure Arc MSI, status code 401 is expected on the first request.${message}`);
2452
+ throw new AuthenticationError(response.status, `${msiName$3}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
2371
2453
  }
2372
2454
  const authHeader = response.headers.get("www-authenticate") || "";
2373
2455
  try {
@@ -2378,32 +2460,113 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
2378
2460
  }
2379
2461
  }
2380
2462
  const arcMsi = {
2381
- async isAvailable() {
2463
+ async isAvailable(scopes) {
2464
+ const resource = mapScopesToResource(scopes);
2465
+ if (!resource) {
2466
+ logger$c.info(`${msiName$3}: Unavailable. Multiple scopes are not supported.`);
2467
+ return false;
2468
+ }
2382
2469
  const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
2383
2470
  if (!result) {
2384
- logger$c.info("The Azure Arc MSI is unavailable.");
2471
+ logger$c.info(`${msiName$3}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
2385
2472
  }
2386
2473
  return result;
2387
2474
  },
2388
- async getToken(identityClient, resource, clientId, getTokenOptions = {}) {
2475
+ async getToken(configuration, getTokenOptions = {}) {
2389
2476
  var _a;
2390
- logger$c.info(`Using the Azure Arc MSI to authenticate.`);
2477
+ const { identityClient, scopes, clientId } = configuration;
2478
+ logger$c.info(`${msiName$3}: Authenticating.`);
2391
2479
  if (clientId) {
2392
- throw new Error("User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.");
2480
+ throw new Error(`${msiName$3}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`);
2393
2481
  }
2394
- const requestOptions = Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal, spanOptions: getTokenOptions.tracingOptions && getTokenOptions.tracingOptions.spanOptions }, prepareRequestOptions$3(resource));
2482
+ const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions$3(scopes)), { allowInsecureConnection: true });
2395
2483
  const filePath = await filePathRequest(identityClient, requestOptions);
2396
2484
  if (!filePath) {
2397
- throw new Error("Azure Arc MSI failed to find the token file.");
2485
+ throw new Error(`${msiName$3}: Failed to find the token file.`);
2398
2486
  }
2399
- const key = await readFileAsync(filePath, { encoding: "utf-8" });
2487
+ const key = await readFileAsync$1(filePath, { encoding: "utf-8" });
2400
2488
  (_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
2401
2489
  return msiGenericGetToken(identityClient, requestOptions, expiresInParser$3, getTokenOptions);
2402
2490
  }
2403
2491
  };
2404
2492
 
2405
2493
  // Copyright (c) Microsoft Corporation.
2406
- const logger$d = credentialLogger("ManagedIdentityCredential");
2494
+ const msiName$4 = "ManagedIdentityCredential - Token Exchange";
2495
+ const logger$d = credentialLogger(msiName$4);
2496
+ const readFileAsync$2 = util.promisify(fs__default.readFile);
2497
+ function expiresInParser$4(requestBody) {
2498
+ // Parses a string representation of the seconds since epoch into a number value
2499
+ return Number(requestBody.expires_on);
2500
+ }
2501
+ function prepareRequestOptions$4(scopes, clientAssertion, clientId) {
2502
+ var _a;
2503
+ const bodyParams = {
2504
+ scope: Array.isArray(scopes) ? scopes.join(" ") : scopes,
2505
+ client_assertion: clientAssertion,
2506
+ client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
2507
+ client_id: clientId,
2508
+ grant_type: "client_credentials"
2509
+ };
2510
+ const urlParams = new URLSearchParams(bodyParams);
2511
+ 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);
2512
+ return {
2513
+ url: url.toString(),
2514
+ method: "POST",
2515
+ body: urlParams.toString(),
2516
+ headers: coreRestPipeline.createHttpHeaders({
2517
+ Accept: "application/json"
2518
+ })
2519
+ };
2520
+ }
2521
+ function tokenExchangeMsi() {
2522
+ const azureFederatedTokenFilePath = process.env.AZURE_FEDERATED_TOKEN_FILE;
2523
+ let azureFederatedTokenFileContent = undefined;
2524
+ let cacheDate = undefined;
2525
+ // Only reads from the assertion file once every 5 minutes
2526
+ async function readAssertion() {
2527
+ // Cached assertions expire after 5 minutes
2528
+ if (cacheDate !== undefined && Date.now() - cacheDate >= 1000 * 60 * 5) {
2529
+ azureFederatedTokenFileContent = undefined;
2530
+ }
2531
+ if (!azureFederatedTokenFileContent) {
2532
+ const file = await readFileAsync$2(azureFederatedTokenFilePath, "utf8");
2533
+ const value = file.trim();
2534
+ if (!value) {
2535
+ throw new Error(`No content on the file ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`);
2536
+ }
2537
+ else {
2538
+ azureFederatedTokenFileContent = value;
2539
+ cacheDate = Date.now();
2540
+ }
2541
+ }
2542
+ return azureFederatedTokenFileContent;
2543
+ }
2544
+ return {
2545
+ async isAvailable(_scopes, _identityClient, clientId) {
2546
+ const env = process.env;
2547
+ const result = Boolean((clientId || env.AZURE_CLIENT_ID) && env.AZURE_TENANT_ID && azureFederatedTokenFilePath);
2548
+ if (!result) {
2549
+ 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`);
2550
+ }
2551
+ return result;
2552
+ },
2553
+ async getToken(configuration, getTokenOptions = {}) {
2554
+ const { identityClient, scopes, clientId } = configuration;
2555
+ logger$d.info(`${msiName$4}: Using the client assertion coming from environment variables.`);
2556
+ let assertion;
2557
+ try {
2558
+ assertion = await readAssertion();
2559
+ }
2560
+ catch (err) {
2561
+ throw new Error(`${msiName$4}: Failed to read ${azureFederatedTokenFilePath}, indicated by the environment variable AZURE_FEDERATED_TOKEN_FILE`);
2562
+ }
2563
+ return msiGenericGetToken(identityClient, prepareRequestOptions$4(scopes, assertion, clientId || process.env.AZURE_CLIENT_ID), expiresInParser$4, getTokenOptions);
2564
+ }
2565
+ };
2566
+ }
2567
+
2568
+ // Copyright (c) Microsoft Corporation.
2569
+ const logger$e = credentialLogger("ManagedIdentityCredential");
2407
2570
  /**
2408
2571
  * Attempts authentication using a managed identity that has been assigned
2409
2572
  * to the deployment environment. This authentication type works in Azure VMs,
@@ -2430,15 +2593,15 @@ class ManagedIdentityCredential {
2430
2593
  this.identityClient = new IdentityClient(clientIdOrOptions);
2431
2594
  }
2432
2595
  }
2433
- async cachedAvailableMSI(resource, clientId, getTokenOptions) {
2596
+ async cachedAvailableMSI(scopes, clientId, getTokenOptions) {
2434
2597
  if (this.cachedMSI) {
2435
2598
  return this.cachedMSI;
2436
2599
  }
2437
2600
  // "fabricMsi" can't be added yet because our HTTPs pipeline doesn't allow skipping the SSL verification step,
2438
2601
  // which is necessary since Service Fabric only provides self-signed certificates on their Identity Endpoint.
2439
- const MSIs = [appServiceMsi2017, cloudShellMsi, arcMsi, imdsMsi];
2602
+ const MSIs = [appServiceMsi2017, cloudShellMsi, arcMsi, tokenExchangeMsi(), imdsMsi];
2440
2603
  for (const msi of MSIs) {
2441
- if (await msi.isAvailable(this.identityClient, resource, clientId, getTokenOptions)) {
2604
+ if (await msi.isAvailable(scopes, this.identityClient, clientId, getTokenOptions)) {
2442
2605
  this.cachedMSI = msi;
2443
2606
  return msi;
2444
2607
  }
@@ -2446,12 +2609,15 @@ class ManagedIdentityCredential {
2446
2609
  throw new CredentialUnavailableError("ManagedIdentityCredential - No MSI credential available");
2447
2610
  }
2448
2611
  async authenticateManagedIdentity(scopes, clientId, getTokenOptions) {
2449
- const resource = mapScopesToResource(scopes);
2450
2612
  const { span, updatedOptions } = createSpan("ManagedIdentityCredential-authenticateManagedIdentity", getTokenOptions);
2451
2613
  try {
2452
2614
  // Determining the available MSI, and avoiding checking for other MSIs while the program is running.
2453
- const availableMSI = await this.cachedAvailableMSI(resource, clientId, updatedOptions);
2454
- return availableMSI.getToken(this.identityClient, resource, clientId, updatedOptions);
2615
+ const availableMSI = await this.cachedAvailableMSI(scopes, clientId, updatedOptions);
2616
+ return availableMSI.getToken({
2617
+ identityClient: this.identityClient,
2618
+ scopes,
2619
+ clientId
2620
+ }, updatedOptions);
2455
2621
  }
2456
2622
  catch (err) {
2457
2623
  span.setStatus({
@@ -2490,7 +2656,7 @@ class ManagedIdentityCredential {
2490
2656
  // It also means that the endpoint answered with either 200 or 201 (see the sendTokenRequest method),
2491
2657
  // yet we had no access token. For this reason, we'll throw once with a specific message:
2492
2658
  const error = new CredentialUnavailableError("The managed identity endpoint was reached, yet no tokens were received.");
2493
- logger$d.getToken.info(formatError(scopes, error));
2659
+ logger$e.getToken.info(formatError(scopes, error));
2494
2660
  throw error;
2495
2661
  }
2496
2662
  // Since `authenticateManagedIdentity` didn't throw, and the result was not null,
@@ -2502,10 +2668,10 @@ class ManagedIdentityCredential {
2502
2668
  // We've previously determined that the endpoint was unavailable,
2503
2669
  // either because it was unreachable or permanently unable to authenticate.
2504
2670
  const error = new CredentialUnavailableError("The managed identity endpoint is not currently available");
2505
- logger$d.getToken.info(formatError(scopes, error));
2671
+ logger$e.getToken.info(formatError(scopes, error));
2506
2672
  throw error;
2507
2673
  }
2508
- logger$d.getToken.info(formatSuccess(scopes));
2674
+ logger$e.getToken.info(formatSuccess(scopes));
2509
2675
  return result;
2510
2676
  }
2511
2677
  catch (err) {
@@ -2526,21 +2692,21 @@ class ManagedIdentityCredential {
2526
2692
  // If either the network is unreachable,
2527
2693
  // we can safely assume the credential is unavailable.
2528
2694
  if (err.code === "ENETUNREACH") {
2529
- const error = new CredentialUnavailableError("ManagedIdentityCredential is unavailable. Network unreachable.");
2530
- logger$d.getToken.info(formatError(scopes, error));
2695
+ const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. Network unreachable. Message: ${err.message}`);
2696
+ logger$e.getToken.info(formatError(scopes, error));
2531
2697
  throw error;
2532
2698
  }
2533
2699
  // If either the host was unreachable,
2534
2700
  // we can safely assume the credential is unavailable.
2535
2701
  if (err.code === "EHOSTUNREACH") {
2536
- const error = new CredentialUnavailableError("ManagedIdentityCredential is unavailable. No managed identity endpoint found.");
2537
- logger$d.getToken.info(formatError(scopes, error));
2702
+ const error = new CredentialUnavailableError(`ManagedIdentityCredential is unavailable. No managed identity endpoint found. Message: ${err.message}`);
2703
+ logger$e.getToken.info(formatError(scopes, error));
2538
2704
  throw error;
2539
2705
  }
2540
2706
  // If err.statusCode has a value of 400, it comes from sendTokenRequest,
2541
2707
  // and it means that the endpoint is working, but that no identity is available.
2542
2708
  if (err.statusCode === 400) {
2543
- throw new CredentialUnavailableError("The managed identity endpoint is indicating there's no available identity");
2709
+ throw new CredentialUnavailableError(`ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
2544
2710
  }
2545
2711
  // If the error has no status code, we can assume there was no available identity.
2546
2712
  // This will throw silently during any ChainedTokenCredential.
@@ -2599,19 +2765,16 @@ const defaultCredentials = [
2599
2765
  *
2600
2766
  * Consult the documentation of these credential types for more information
2601
2767
  * on how they attempt authentication.
2602
- *
2603
- * **Note**: `VisualStudioCodeCredential` is provided by an extension package:
2604
- * `@azure/identity-vscode`. If this package is not installed and registered
2605
- * using the extension API (`useIdentityExtension`), then authentication using
2606
- * `VisualStudioCodeCredential` will not be available.
2607
- *
2608
- * Azure Identity extensions may add credential types to the default credential
2609
- * stack.
2610
2768
  */
2611
2769
  class DefaultAzureCredential extends ChainedTokenCredential {
2612
2770
  /**
2613
2771
  * Creates an instance of the DefaultAzureCredential class.
2614
2772
  *
2773
+ * **Note**: `VisualStudioCodeCredential` is provided by a plugin package:
2774
+ * `@azure/identity-vscode`. If this package is not installed and registered
2775
+ * using the plugin API (`useIdentityPlugin`), then authentication using
2776
+ * `VisualStudioCodeCredential` will not be available.
2777
+ *
2615
2778
  * @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.
2616
2779
  */
2617
2780
  constructor(options) {
@@ -2765,7 +2928,7 @@ class MsalOpenBrowser extends MsalNode {
2765
2928
  }
2766
2929
 
2767
2930
  // Copyright (c) Microsoft Corporation.
2768
- const logger$e = credentialLogger("InteractiveBrowserCredential");
2931
+ const logger$f = credentialLogger("InteractiveBrowserCredential");
2769
2932
  /**
2770
2933
  * Enables authentication to Azure Active Directory inside of the web browser
2771
2934
  * using the interactive login flow.
@@ -2787,7 +2950,7 @@ class InteractiveBrowserCredential {
2787
2950
  const redirectUri = typeof options.redirectUri === "function"
2788
2951
  ? options.redirectUri()
2789
2952
  : options.redirectUri || "http://localhost";
2790
- this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$e,
2953
+ this.msalFlow = new MsalOpenBrowser(Object.assign(Object.assign({}, options), { tokenCredentialOptions: options, logger: logger$f,
2791
2954
  redirectUri }));
2792
2955
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
2793
2956
  }
@@ -2865,7 +3028,7 @@ class MsalDeviceCode extends MsalNode {
2865
3028
  }
2866
3029
 
2867
3030
  // Copyright (c) Microsoft Corporation.
2868
- const logger$f = credentialLogger("DeviceCodeCredential");
3031
+ const logger$g = credentialLogger("DeviceCodeCredential");
2869
3032
  /**
2870
3033
  * Method that logs the user code from the DeviceCodeCredential.
2871
3034
  * @param deviceCodeInfo - The device code.
@@ -2885,7 +3048,7 @@ class DeviceCodeCredential {
2885
3048
  * @param options - Options for configuring the client which makes the authentication requests.
2886
3049
  */
2887
3050
  constructor(options) {
2888
- this.msalFlow = new MsalDeviceCode(Object.assign(Object.assign({}, options), { logger: logger$f, userPromptCallback: (options === null || options === void 0 ? void 0 : options.userPromptCallback) || defaultDeviceCodePromptCallback, tokenCredentialOptions: options || {} }));
3051
+ this.msalFlow = new MsalDeviceCode(Object.assign(Object.assign({}, options), { logger: logger$g, userPromptCallback: (options === null || options === void 0 ? void 0 : options.userPromptCallback) || defaultDeviceCodePromptCallback, tokenCredentialOptions: options || {} }));
2889
3052
  this.disableAutomaticAuthentication = options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication;
2890
3053
  }
2891
3054
  /**
@@ -2926,7 +3089,45 @@ class DeviceCodeCredential {
2926
3089
  }
2927
3090
 
2928
3091
  // Copyright (c) Microsoft Corporation.
2929
- const logger$g = credentialLogger("AuthorizationCodeCredential");
3092
+ /**
3093
+ * 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`
3094
+ * to trigger the authentication flow, and then respond based on the values obtained from the redirect callback
3095
+ * @internal
3096
+ */
3097
+ class MsalAuthorizationCode extends MsalNode {
3098
+ constructor(options) {
3099
+ super(options);
3100
+ this.logger = credentialLogger("NodeJS MSAL Authorization Code");
3101
+ this.redirectUri = options.redirectUri;
3102
+ this.authorizationCode = options.authorizationCode;
3103
+ if (options.clientSecret) {
3104
+ this.msalConfig.auth.clientSecret = options.clientSecret;
3105
+ }
3106
+ }
3107
+ async getAuthCodeUrl(options) {
3108
+ await this.init();
3109
+ return this.confidentialApp.getAuthCodeUrl(options);
3110
+ }
3111
+ async doGetToken(scopes, options) {
3112
+ var _a;
3113
+ try {
3114
+ const result = await ((_a = this.confidentialApp) === null || _a === void 0 ? void 0 : _a.acquireTokenByCode({
3115
+ scopes,
3116
+ redirectUri: this.redirectUri,
3117
+ code: this.authorizationCode
3118
+ }));
3119
+ // The Client Credential flow does not return an account,
3120
+ // so each time getToken gets called, we will have to acquire a new token through the service.
3121
+ return this.handleResult(scopes, this.clientId, result || undefined);
3122
+ }
3123
+ catch (err) {
3124
+ throw this.handleError(scopes, err, options);
3125
+ }
3126
+ }
3127
+ }
3128
+
3129
+ // Copyright (c) Microsoft Corporation.
3130
+ const logger$h = credentialLogger("AuthorizationCodeCredential");
2930
3131
  /**
2931
3132
  * Enables authentication to Azure Active Directory using an authorization code
2932
3133
  * that was obtained through the authorization code flow, described in more detail
@@ -2940,26 +3141,23 @@ class AuthorizationCodeCredential {
2940
3141
  * @internal
2941
3142
  */
2942
3143
  constructor(tenantId, clientId, clientSecretOrAuthorizationCode, authorizationCodeOrRedirectUri, redirectUriOrOptions, options) {
2943
- this.lastTokenResponse = null;
2944
- checkTenantId(logger$g, tenantId);
2945
- this.clientId = clientId;
2946
- this.tenantId = tenantId;
3144
+ checkTenantId(logger$h, tenantId);
3145
+ let clientSecret = clientSecretOrAuthorizationCode;
2947
3146
  if (typeof redirectUriOrOptions === "string") {
2948
3147
  // the clientId+clientSecret constructor
2949
- this.clientSecret = clientSecretOrAuthorizationCode;
2950
3148
  this.authorizationCode = authorizationCodeOrRedirectUri;
2951
3149
  this.redirectUri = redirectUriOrOptions;
2952
3150
  // options okay
2953
3151
  }
2954
3152
  else {
2955
3153
  // clientId only
2956
- this.clientSecret = undefined;
2957
3154
  this.authorizationCode = clientSecretOrAuthorizationCode;
2958
3155
  this.redirectUri = authorizationCodeOrRedirectUri;
3156
+ clientSecret = undefined;
2959
3157
  options = redirectUriOrOptions;
2960
3158
  }
2961
- this.allowMultiTenantAuthentication = options === null || options === void 0 ? void 0 : options.allowMultiTenantAuthentication;
2962
- this.identityClient = new IdentityClient(options);
3159
+ this.msalFlow = new MsalAuthorizationCode(Object.assign(Object.assign({}, options), { clientSecret,
3160
+ clientId, tokenCredentialOptions: options || {}, logger: logger$h, redirectUri: this.redirectUri, authorizationCode: this.authorizationCode }));
2963
3161
  }
2964
3162
  /**
2965
3163
  * Authenticates with Azure Active Directory and returns an access token if successful.
@@ -2969,67 +3167,11 @@ class AuthorizationCodeCredential {
2969
3167
  * @param options - The options used to configure any requests this
2970
3168
  * TokenCredential implementation might make.
2971
3169
  */
2972
- async getToken(scopes, options) {
2973
- var _a, _b;
2974
- const tenantId = processMultiTenantRequest(this.tenantId, this.allowMultiTenantAuthentication, options) ||
2975
- this.tenantId;
2976
- const { span, updatedOptions } = createSpan("AuthorizationCodeCredential-getToken", options);
2977
- try {
2978
- let tokenResponse = null;
2979
- let scopeString = typeof scopes === "string" ? scopes : scopes.join(" ");
2980
- if (scopeString.indexOf("offline_access") < 0) {
2981
- scopeString += " offline_access";
2982
- }
2983
- // Try to use the refresh token first
2984
- if (this.lastTokenResponse && this.lastTokenResponse.refreshToken) {
2985
- tokenResponse = await this.identityClient.refreshAccessToken(tenantId, this.clientId, scopeString, this.lastTokenResponse.refreshToken, this.clientSecret, undefined, updatedOptions);
2986
- }
2987
- const query = new URLSearchParams({
2988
- client_id: this.clientId,
2989
- grant_type: "authorization_code",
2990
- scope: scopeString,
2991
- code: this.authorizationCode,
2992
- redirect_uri: this.redirectUri
2993
- });
2994
- if (this.clientSecret) {
2995
- query.set("client_secret", this.clientSecret);
2996
- }
2997
- if (tokenResponse === null) {
2998
- const urlSuffix = getIdentityTokenEndpointSuffix(tenantId);
2999
- const pipelineRequest = coreRestPipeline.createPipelineRequest({
3000
- url: `${this.identityClient.authorityHost}/${tenantId}/${urlSuffix}`,
3001
- method: "POST",
3002
- body: query.toString(),
3003
- headers: coreRestPipeline.createHttpHeaders({
3004
- Accept: "application/json",
3005
- "Content-Type": "application/x-www-form-urlencoded"
3006
- }),
3007
- tracingOptions: {
3008
- spanOptions: (_a = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _a === void 0 ? void 0 : _a.spanOptions,
3009
- tracingContext: (_b = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.tracingOptions) === null || _b === void 0 ? void 0 : _b.tracingContext
3010
- }
3011
- });
3012
- tokenResponse = await this.identityClient.sendTokenRequest(pipelineRequest, (response) => new Date(response === null || response === void 0 ? void 0 : response.expires_on).getTime());
3013
- }
3014
- this.lastTokenResponse = tokenResponse;
3015
- logger$g.getToken.info(formatSuccess(scopes));
3016
- const token = tokenResponse && tokenResponse.accessToken;
3017
- if (!token) {
3018
- throw new CredentialUnavailableError("Failed to retrieve a valid token");
3019
- }
3020
- return token;
3021
- }
3022
- catch (err) {
3023
- span.setStatus({
3024
- code: coreTracing.SpanStatusCode.ERROR,
3025
- message: err.message
3026
- });
3027
- logger$g.getToken.info(formatError(scopes, err));
3028
- throw err;
3029
- }
3030
- finally {
3031
- span.end();
3032
- }
3170
+ async getToken(scopes, options = {}) {
3171
+ return trace(`${this.constructor.name}.getToken`, options, async (newOptions) => {
3172
+ const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
3173
+ return this.msalFlow.getToken(arrayScopes, Object.assign(Object.assign({}, newOptions), { disableAutomaticAuthentication: this.disableAutomaticAuthentication }));
3174
+ });
3033
3175
  }
3034
3176
  }
3035
3177
 
@@ -3049,9 +3191,6 @@ const ApplicationCredentials = [
3049
3191
  *
3050
3192
  * Consult the documentation of these credential types for more information
3051
3193
  * on how they attempt authentication.
3052
- *
3053
- * Azure Identity extensions may add credential types to the default credential
3054
- * stack.
3055
3194
  */
3056
3195
  class ApplicationCredential extends ChainedTokenCredential {
3057
3196
  /**
@@ -3066,6 +3205,116 @@ class ApplicationCredential extends ChainedTokenCredential {
3066
3205
  }
3067
3206
  }
3068
3207
 
3208
+ // Copyright (c) Microsoft Corporation.
3209
+ /**
3210
+ * MSAL on behalf of flow. Calls to MSAL's confidential application's `acquireTokenOnBehalfOf` during `doGetToken`.
3211
+ * @internal
3212
+ */
3213
+ class MsalOnBehalfOf extends MsalNode {
3214
+ constructor(options) {
3215
+ super(options);
3216
+ this.logger.info("Initialized MSAL's On-Behalf-Of flow");
3217
+ this.requiresConfidential = true;
3218
+ this.userAssertionToken = options.userAssertionToken;
3219
+ this.certificatePath = options.certificatePath;
3220
+ this.sendCertificateChain = options.sendCertificateChain;
3221
+ this.clientSecret = options.clientSecret;
3222
+ }
3223
+ // Changing the MSAL configuration asynchronously
3224
+ async init(options) {
3225
+ if (this.certificatePath) {
3226
+ try {
3227
+ const parts = await parseCertificate(this.certificatePath, this.sendCertificateChain);
3228
+ this.msalConfig.auth.clientCertificate = {
3229
+ thumbprint: parts.thumbprint,
3230
+ privateKey: parts.certificateContents,
3231
+ x5c: parts.x5c
3232
+ };
3233
+ }
3234
+ catch (error) {
3235
+ this.logger.info(formatError("", error));
3236
+ throw error;
3237
+ }
3238
+ }
3239
+ else {
3240
+ this.msalConfig.auth.clientSecret = this.clientSecret;
3241
+ }
3242
+ return super.init(options);
3243
+ }
3244
+ async doGetToken(scopes, options = {}) {
3245
+ try {
3246
+ const result = await this.confidentialApp.acquireTokenOnBehalfOf({
3247
+ scopes,
3248
+ correlationId: options.correlationId,
3249
+ authority: options.authority,
3250
+ oboAssertion: this.userAssertionToken
3251
+ });
3252
+ return this.handleResult(scopes, this.clientId, result || undefined);
3253
+ }
3254
+ catch (err) {
3255
+ throw this.handleError(scopes, err, options);
3256
+ }
3257
+ }
3258
+ }
3259
+
3260
+ // Copyright (c) Microsoft Corporation.
3261
+ const credentialName = "OnBehalfOfCredential";
3262
+ const logger$i = credentialLogger(credentialName);
3263
+ /**
3264
+ * 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).
3265
+ */
3266
+ class OnBehalfOfCredential {
3267
+ /**
3268
+ * Creates an instance of the {@link OnBehalfOfCredential} with the details
3269
+ * needed to authenticate against Azure Active Directory with a client
3270
+ * secret or a path to a PEM certificate, and an user assertion.
3271
+ *
3272
+ * Example using the `KeyClient` from [\@azure/keyvault-keys](https://www.npmjs.com/package/\@azure/keyvault-keys):
3273
+ *
3274
+ * ```ts
3275
+ * const tokenCredential = new OnBehalfOfCredential({
3276
+ * tenantId,
3277
+ * clientId,
3278
+ * clientSecret, // or `certificatePath: "/path/to/certificate.pem"
3279
+ * userAssertionToken: "access-token"
3280
+ * });
3281
+ * const client = new KeyClient("vault-url", tokenCredential);
3282
+ *
3283
+ * await client.getKey("key-name");
3284
+ * ```
3285
+ *
3286
+ * @param configuration - Configuration specific to this credential.
3287
+ * @param options - Optional parameters, generally common across credentials.
3288
+ */
3289
+ constructor(configuration, options = {}) {
3290
+ this.configuration = configuration;
3291
+ this.options = options;
3292
+ const { tenantId, clientId, userAssertionToken } = configuration;
3293
+ const secretConfiguration = configuration;
3294
+ const certificateConfiguration = configuration;
3295
+ if (!tenantId ||
3296
+ !clientId ||
3297
+ !(secretConfiguration.clientSecret || certificateConfiguration.certificatePath) ||
3298
+ !userAssertionToken) {
3299
+ throw new Error(`${credentialName}: tenantId, clientId, clientSecret (or certificatePath) and userAssertionToken are required parameters.`);
3300
+ }
3301
+ this.msalFlow = new MsalOnBehalfOf(Object.assign(Object.assign(Object.assign({}, this.options), this.configuration), { logger: logger$i, tokenCredentialOptions: this.options }));
3302
+ }
3303
+ /**
3304
+ * Authenticates with Azure Active Directory and returns an access token if successful.
3305
+ * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
3306
+ *
3307
+ * @param scopes - The list of scopes for which the token will have access.
3308
+ * @param options - The options used to configure the underlying network requests.
3309
+ */
3310
+ async getToken(scopes, options = {}) {
3311
+ return trace(`${credentialName}.getToken`, options, async (newOptions) => {
3312
+ const arrayScopes = Array.isArray(scopes) ? scopes : [scopes];
3313
+ return this.msalFlow.getToken(arrayScopes, newOptions);
3314
+ });
3315
+ }
3316
+ }
3317
+
3069
3318
  // Copyright (c) Microsoft Corporation.
3070
3319
  /**
3071
3320
  * Returns a new instance of the {@link DefaultAzureCredential}.
@@ -3093,11 +3342,12 @@ exports.DeviceCodeCredential = DeviceCodeCredential;
3093
3342
  exports.EnvironmentCredential = EnvironmentCredential;
3094
3343
  exports.InteractiveBrowserCredential = InteractiveBrowserCredential;
3095
3344
  exports.ManagedIdentityCredential = ManagedIdentityCredential;
3345
+ exports.OnBehalfOfCredential = OnBehalfOfCredential;
3096
3346
  exports.UsernamePasswordCredential = UsernamePasswordCredential;
3097
3347
  exports.VisualStudioCodeCredential = VisualStudioCodeCredential;
3098
3348
  exports.deserializeAuthenticationRecord = deserializeAuthenticationRecord;
3099
3349
  exports.getDefaultAzureCredential = getDefaultAzureCredential;
3100
3350
  exports.logger = logger;
3101
3351
  exports.serializeAuthenticationRecord = serializeAuthenticationRecord;
3102
- exports.useIdentityExtension = useIdentityExtension;
3352
+ exports.useIdentityPlugin = useIdentityPlugin;
3103
3353
  //# sourceMappingURL=index.js.map