Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
@@ -0,0 +1,18 @@
import type { GetTokenOptions } from "@azure/core-auth";
import type { IdentityClient } from "../../client/identityClient.js";
/**
* Defines how to determine whether the Azure IMDS MSI is available.
*
* Actually getting the token once we determine IMDS is available is handled by MSAL.
*/
export declare const imdsMsi: {
name: string;
isAvailable(options: {
scopes: string | string[];
identityClient?: IdentityClient;
clientId?: string;
resourceId?: string;
getTokenOptions?: GetTokenOptions;
}): Promise<boolean>;
};
//# sourceMappingURL=imdsMsi.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"imdsMsi.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/imdsMsi.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAIxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAkErE;;;;GAIG;AACH,eAAO,MAAM,OAAO;;yBAES;QACzB,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,eAAe,CAAC,EAAE,eAAe,CAAC;KACnC,GAAG,OAAO,CAAC,OAAO,CAAC;CAmErB,CAAC"}
@@ -0,0 +1,125 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.imdsMsi = void 0;
const core_rest_pipeline_1 = require("@azure/core-rest-pipeline");
const core_util_1 = require("@azure/core-util");
const logging_js_1 = require("../../util/logging.js");
const utils_js_1 = require("./utils.js");
const tracing_js_1 = require("../../util/tracing.js");
const msiName = "ManagedIdentityCredential - IMDS";
const logger = (0, logging_js_1.credentialLogger)(msiName);
const imdsHost = "http://169.254.169.254";
const imdsEndpointPath = "/metadata/identity/oauth2/token";
const imdsApiVersion = "2018-02-01";
/**
* Generates the options used on the request for an access token.
*/
function prepareRequestOptions(scopes, clientId, resourceId, options) {
var _a;
const resource = (0, utils_js_1.mapScopesToResource)(scopes);
if (!resource) {
throw new Error(`${msiName}: Multiple scopes are not supported.`);
}
const { skipQuery, skipMetadataHeader } = options || {};
let query = "";
// Pod Identity will try to process this request even if the Metadata header is missing.
// We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.
if (!skipQuery) {
const queryParameters = {
resource,
"api-version": imdsApiVersion,
};
if (clientId) {
queryParameters.client_id = clientId;
}
if (resourceId) {
queryParameters.msi_res_id = resourceId;
}
const params = new URLSearchParams(queryParameters);
query = `?${params.toString()}`;
}
const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
const rawHeaders = {
Accept: "application/json",
Metadata: "true",
};
// Remove the Metadata header to invoke a request error from some IMDS endpoints.
if (skipMetadataHeader) {
delete rawHeaders.Metadata;
}
return {
// In this case, the `?` should be added in the "query" variable `skipQuery` is not set.
url: `${url}${query}`,
method: "GET",
headers: (0, core_rest_pipeline_1.createHttpHeaders)(rawHeaders),
};
}
/**
* Defines how to determine whether the Azure IMDS MSI is available.
*
* Actually getting the token once we determine IMDS is available is handled by MSAL.
*/
exports.imdsMsi = {
name: "imdsMsi",
async isAvailable(options) {
const { scopes, identityClient, clientId, resourceId, getTokenOptions } = options;
const resource = (0, utils_js_1.mapScopesToResource)(scopes);
if (!resource) {
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
return false;
}
// if the PodIdentityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
return true;
}
if (!identityClient) {
throw new Error("Missing IdentityClient");
}
const requestOptions = prepareRequestOptions(resource, clientId, resourceId, {
skipMetadataHeader: true,
skipQuery: true,
});
return tracing_js_1.tracingClient.withSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions !== null && getTokenOptions !== void 0 ? getTokenOptions : {}, async (updatedOptions) => {
var _a, _b;
requestOptions.tracingOptions = updatedOptions.tracingOptions;
// Create a request with a timeout since we expect that
// not having a "Metadata" header should cause an error to be
// returned quickly from the endpoint, proving its availability.
const request = (0, core_rest_pipeline_1.createPipelineRequest)(requestOptions);
// Default to 1000 if the default of 0 is used.
// Negative values can still be used to disable the timeout.
request.timeout = ((_a = updatedOptions.requestOptions) === null || _a === void 0 ? void 0 : _a.timeout) || 1000;
// This MSI uses the imdsEndpoint to get the token, which only uses http://
request.allowInsecureConnection = true;
let response;
try {
logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);
response = await identityClient.sendRequest(request);
}
catch (err) {
// If the request failed, or Node.js was unable to establish a connection,
// or the host was down, we'll assume the IMDS endpoint isn't available.
if ((0, core_util_1.isError)(err)) {
logger.verbose(`${msiName}: Caught error ${err.name}: ${err.message}`);
}
// This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
// rather than just timing out, as expected.
logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);
return false;
}
if (response.status === 403) {
if ((_b = response.bodyAsText) === null || _b === void 0 ? void 0 : _b.includes("unreachable")) {
logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);
logger.info(`${msiName}: ${response.bodyAsText}`);
return false;
}
}
// If we received any response, the endpoint is available
logger.info(`${msiName}: The Azure IMDS endpoint is available`);
return true;
});
},
};
//# sourceMappingURL=imdsMsi.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,12 @@
import type { PipelinePolicy } from "@azure/core-rest-pipeline";
import type { MSIConfiguration } from "./models.js";
/**
* An additional policy that retries on 404 errors. The default retry policy does not retry on
* 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy
* will retry on 404s with an exponential backoff.
*
* @param msiRetryConfig - The retry configuration for the MSI credential.
* @returns - The policy that will retry on 404s.
*/
export declare function imdsRetryPolicy(msiRetryConfig: MSIConfiguration["retryConfig"]): PipelinePolicy;
//# sourceMappingURL=imdsRetryPolicy.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"imdsRetryPolicy.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/imdsRetryPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,cAAc,EAAE,gBAAgB,CAAC,aAAa,CAAC,GAAG,cAAc,CAqB/F"}
@@ -0,0 +1,36 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.imdsRetryPolicy = imdsRetryPolicy;
const core_rest_pipeline_1 = require("@azure/core-rest-pipeline");
const core_util_1 = require("@azure/core-util");
// Matches the default retry configuration in expontentialRetryStrategy.ts
const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;
/**
* An additional policy that retries on 404 errors. The default retry policy does not retry on
* 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy
* will retry on 404s with an exponential backoff.
*
* @param msiRetryConfig - The retry configuration for the MSI credential.
* @returns - The policy that will retry on 404s.
*/
function imdsRetryPolicy(msiRetryConfig) {
return (0, core_rest_pipeline_1.retryPolicy)([
{
name: "imdsRetryPolicy",
retry: ({ retryCount, response }) => {
if ((response === null || response === void 0 ? void 0 : response.status) !== 404) {
return { skipStrategy: true };
}
return (0, core_util_1.calculateRetryDelay)(retryCount, {
retryDelayInMs: msiRetryConfig.startDelayInMs,
maxRetryDelayInMs: DEFAULT_CLIENT_MAX_RETRY_INTERVAL,
});
},
},
], {
maxRetries: msiRetryConfig.maxRetries,
});
}
//# sourceMappingURL=imdsRetryPolicy.js.map
@@ -0,0 +1 @@
{"version":3,"file":"imdsRetryPolicy.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/imdsRetryPolicy.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;AAmBlC,0CAqBC;AArCD,kEAAwD;AAGxD,gDAAuD;AAEvD,0EAA0E;AAC1E,MAAM,iCAAiC,GAAG,IAAI,GAAG,EAAE,CAAC;AAEpD;;;;;;;GAOG;AACH,SAAgB,eAAe,CAAC,cAA+C;IAC7E,OAAO,IAAA,gCAAW,EAChB;QACE;YACE,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;gBAClC,IAAI,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,MAAM,MAAK,GAAG,EAAE,CAAC;oBAC7B,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;gBAChC,CAAC;gBAED,OAAO,IAAA,+BAAmB,EAAC,UAAU,EAAE;oBACrC,cAAc,EAAE,cAAc,CAAC,cAAc;oBAC7C,iBAAiB,EAAE,iCAAiC;iBACrD,CAAC,CAAC;YACL,CAAC;SACF;KACF,EACD;QACE,UAAU,EAAE,cAAc,CAAC,UAAU;KACtC,CACF,CAAC;AACJ,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PipelinePolicy } from \"@azure/core-rest-pipeline\";\nimport { retryPolicy } from \"@azure/core-rest-pipeline\";\n\nimport type { MSIConfiguration } from \"./models.js\";\nimport { calculateRetryDelay } from \"@azure/core-util\";\n\n// Matches the default retry configuration in expontentialRetryStrategy.ts\nconst DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64;\n\n/**\n * An additional policy that retries on 404 errors. The default retry policy does not retry on\n * 404s, but the IMDS endpoint can return 404s when the token is not yet available. This policy\n * will retry on 404s with an exponential backoff.\n *\n * @param msiRetryConfig - The retry configuration for the MSI credential.\n * @returns - The policy that will retry on 404s.\n */\nexport function imdsRetryPolicy(msiRetryConfig: MSIConfiguration[\"retryConfig\"]): PipelinePolicy {\n return retryPolicy(\n [\n {\n name: \"imdsRetryPolicy\",\n retry: ({ retryCount, response }) => {\n if (response?.status !== 404) {\n return { skipStrategy: true };\n }\n\n return calculateRetryDelay(retryCount, {\n retryDelayInMs: msiRetryConfig.startDelayInMs,\n maxRetryDelayInMs: DEFAULT_CLIENT_MAX_RETRY_INTERVAL,\n });\n },\n },\n ],\n {\n maxRetries: msiRetryConfig.maxRetries,\n },\n );\n}\n"]}
@@ -0,0 +1,61 @@
import type { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth";
import type { TokenCredentialOptions } from "../../tokenCredentialOptions.js";
import type { ManagedIdentityCredentialClientIdOptions, ManagedIdentityCredentialObjectIdOptions, ManagedIdentityCredentialResourceIdOptions } from "./options.js";
/**
* Attempts authentication using a managed identity available at the deployment environment.
* This authentication type works in Azure VMs, App Service instances, Azure Functions applications,
* Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell.
*
* More information about configuring managed identities can be found here:
* https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
*/
export declare class ManagedIdentityCredential implements TokenCredential {
private managedIdentityApp;
private identityClient;
private clientId?;
private resourceId?;
private objectId?;
private msiRetryConfig;
private isAvailableIdentityClient;
/**
* Creates an instance of ManagedIdentityCredential with the client ID of a
* user-assigned identity, or app registration (when working with AKS pod-identity).
*
* @param clientId - The client ID of the user-assigned identity, or app registration (when working with AKS pod-identity).
* @param options - Options for configuring the client which makes the access token request.
*/
constructor(clientId: string, options?: TokenCredentialOptions);
/**
* Creates an instance of ManagedIdentityCredential with a client ID
*
* @param options - Options for configuring the client which makes the access token request.
*/
constructor(options?: ManagedIdentityCredentialClientIdOptions);
/**
* Creates an instance of ManagedIdentityCredential with a resource ID
*
* @param options - Options for configuring the resource which makes the access token request.
*/
constructor(options?: ManagedIdentityCredentialResourceIdOptions);
/**
* Creates an instance of ManagedIdentityCredential with an object ID
*
* @param options - Options for configuring the resource which makes the access token request.
*/
constructor(options?: ManagedIdentityCredentialObjectIdOptions);
/**
* Authenticates with Microsoft Entra ID and returns an access token if successful.
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
* If an unexpected error occurs, an {@link AuthenticationError} will be thrown with the details of the failure.
*
* @param scopes - The list of scopes for which the token will have access.
* @param options - The options used to configure any requests this
* TokenCredential implementation might make.
*/
getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
/**
* Ensures the validity of the MSAL token
*/
private ensureValidMsalToken;
}
//# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAc9E,OAAO,KAAK,EACV,wCAAwC,EACxC,wCAAwC,EACxC,0CAA0C,EAC3C,MAAM,cAAc,CAAC;AAItB;;;;;;;GAOG;AACH,qBAAa,yBAA0B,YAAW,eAAe;IAC/D,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,cAAc,CAIpB;IACF,OAAO,CAAC,yBAAyB,CAAiB;IAElD;;;;;;OAMG;gBACS,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAC9D;;;;OAIG;gBACS,OAAO,CAAC,EAAE,wCAAwC;IAC9D;;;;OAIG;gBACS,OAAO,CAAC,EAAE,0CAA0C;IAChE;;;;OAIG;gBACS,OAAO,CAAC,EAAE,wCAAwC;IA4G9D;;;;;;;;OAQG;IACU,QAAQ,CACnB,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,WAAW,CAAC;IAyGvB;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAuB7B"}
@@ -0,0 +1,233 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ManagedIdentityCredential = void 0;
const logger_1 = require("@azure/logger");
const msal_node_1 = require("@azure/msal-node");
const identityClient_js_1 = require("../../client/identityClient.js");
const errors_js_1 = require("../../errors.js");
const utils_js_1 = require("../../msal/utils.js");
const imdsRetryPolicy_js_1 = require("./imdsRetryPolicy.js");
const logging_js_1 = require("../../util/logging.js");
const tracing_js_1 = require("../../util/tracing.js");
const imdsMsi_js_1 = require("./imdsMsi.js");
const tokenExchangeMsi_js_1 = require("./tokenExchangeMsi.js");
const utils_js_2 = require("./utils.js");
const logger = (0, logging_js_1.credentialLogger)("ManagedIdentityCredential");
/**
* Attempts authentication using a managed identity available at the deployment environment.
* This authentication type works in Azure VMs, App Service instances, Azure Functions applications,
* Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell.
*
* More information about configuring managed identities can be found here:
* https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
*/
class ManagedIdentityCredential {
/**
* @internal
* @hidden
*/
constructor(clientIdOrOptions, options) {
var _a, _b;
this.msiRetryConfig = {
maxRetries: 5,
startDelayInMs: 800,
intervalIncrement: 2,
};
let _options;
if (typeof clientIdOrOptions === "string") {
this.clientId = clientIdOrOptions;
_options = options !== null && options !== void 0 ? options : {};
}
else {
this.clientId = clientIdOrOptions === null || clientIdOrOptions === void 0 ? void 0 : clientIdOrOptions.clientId;
_options = clientIdOrOptions !== null && clientIdOrOptions !== void 0 ? clientIdOrOptions : {};
}
this.resourceId = _options === null || _options === void 0 ? void 0 : _options.resourceId;
this.objectId = _options === null || _options === void 0 ? void 0 : _options.objectId;
// For JavaScript users.
const providedIds = [this.clientId, this.resourceId, this.objectId].filter(Boolean);
if (providedIds.length > 1) {
throw new Error(`ManagedIdentityCredential: only one of 'clientId', 'resourceId', or 'objectId' can be provided. Received values: ${JSON.stringify({ clientId: this.clientId, resourceId: this.resourceId, objectId: this.objectId })}`);
}
// ManagedIdentity uses http for local requests
_options.allowInsecureConnection = true;
if (((_a = _options.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== undefined) {
this.msiRetryConfig.maxRetries = _options.retryOptions.maxRetries;
}
this.identityClient = new identityClient_js_1.IdentityClient(Object.assign(Object.assign({}, _options), { additionalPolicies: [{ policy: (0, imdsRetryPolicy_js_1.imdsRetryPolicy)(this.msiRetryConfig), position: "perCall" }] }));
this.managedIdentityApp = new msal_node_1.ManagedIdentityApplication({
managedIdentityIdParams: {
userAssignedClientId: this.clientId,
userAssignedResourceId: this.resourceId,
userAssignedObjectId: this.objectId,
},
system: {
disableInternalRetries: true,
networkClient: this.identityClient,
loggerOptions: {
logLevel: (0, utils_js_1.getMSALLogLevel)((0, logger_1.getLogLevel)()),
piiLoggingEnabled: (_b = _options.loggingOptions) === null || _b === void 0 ? void 0 : _b.enableUnsafeSupportLogging,
loggerCallback: (0, utils_js_1.defaultLoggerCallback)(logger),
},
},
});
this.isAvailableIdentityClient = new identityClient_js_1.IdentityClient(Object.assign(Object.assign({}, _options), { retryOptions: {
maxRetries: 0,
} }));
const managedIdentitySource = this.managedIdentityApp.getManagedIdentitySource();
// CloudShell MSI will ignore any user-assigned identity passed as parameters. To avoid confusion, we prevent this from happening as early as possible.
if (managedIdentitySource === "CloudShell") {
if (this.clientId || this.resourceId || this.objectId) {
logger.warning(`CloudShell MSI detected with user-provided IDs - throwing. Received values: ${JSON.stringify({
clientId: this.clientId,
resourceId: this.resourceId,
objectId: this.objectId,
})}.`);
throw new errors_js_1.CredentialUnavailableError("ManagedIdentityCredential: Specifying a user-assigned managed identity is not supported for CloudShell at runtime. When using Managed Identity in CloudShell, omit the clientId, resourceId, and objectId parameters.");
}
}
// ServiceFabric does not support specifying user-assigned managed identity by client ID or resource ID. The managed identity selected is based on the resource configuration.
if (managedIdentitySource === "ServiceFabric") {
if (this.clientId || this.resourceId || this.objectId) {
logger.warning(`Service Fabric detected with user-provided IDs - throwing. Received values: ${JSON.stringify({
clientId: this.clientId,
resourceId: this.resourceId,
objectId: this.objectId,
})}.`);
throw new errors_js_1.CredentialUnavailableError(`ManagedIdentityCredential: ${utils_js_2.serviceFabricErrorMessage}`);
}
}
}
/**
* Authenticates with Microsoft Entra ID and returns an access token if successful.
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
* If an unexpected error occurs, an {@link AuthenticationError} will be thrown with the details of the failure.
*
* @param scopes - The list of scopes for which the token will have access.
* @param options - The options used to configure any requests this
* TokenCredential implementation might make.
*/
async getToken(scopes, options = {}) {
logger.getToken.info("Using the MSAL provider for Managed Identity.");
const resource = (0, utils_js_2.mapScopesToResource)(scopes);
if (!resource) {
throw new errors_js_1.CredentialUnavailableError(`ManagedIdentityCredential: Multiple scopes are not supported. Scopes: ${JSON.stringify(scopes)}`);
}
return tracing_js_1.tracingClient.withSpan("ManagedIdentityCredential.getToken", options, async () => {
var _a;
try {
const isTokenExchangeMsi = await tokenExchangeMsi_js_1.tokenExchangeMsi.isAvailable(this.clientId);
// Most scenarios are handled by MSAL except for two:
// AKS pod identity - MSAL does not implement the token exchange flow.
// IMDS Endpoint probing - MSAL does not do any probing before trying to get a token.
// As a DefaultAzureCredential optimization we probe the IMDS endpoint with a short timeout and no retries before actually trying to get a token
// We will continue to implement these features in the Identity library.
const identitySource = this.managedIdentityApp.getManagedIdentitySource();
const isImdsMsi = identitySource === "DefaultToImds" || identitySource === "Imds"; // Neither actually checks that IMDS endpoint is available, just that it's the source the MSAL _would_ try to use.
logger.getToken.info(`MSAL Identity source: ${identitySource}`);
if (isTokenExchangeMsi) {
// In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
logger.getToken.info("Using the token exchange managed identity.");
const result = await tokenExchangeMsi_js_1.tokenExchangeMsi.getToken({
scopes,
clientId: this.clientId,
identityClient: this.identityClient,
retryConfig: this.msiRetryConfig,
resourceId: this.resourceId,
});
if (result === null) {
throw new errors_js_1.CredentialUnavailableError("Attempted to use the token exchange managed identity, but received a null response.");
}
return result;
}
else if (isImdsMsi) {
// In the IMDS scenario we will probe the IMDS endpoint to ensure it's available before trying to get a token.
// If the IMDS endpoint is not available and this is the source that MSAL will use, we will fail-fast with an error that tells DAC to move to the next credential.
logger.getToken.info("Using the IMDS endpoint to probe for availability.");
const isAvailable = await imdsMsi_js_1.imdsMsi.isAvailable({
scopes,
clientId: this.clientId,
getTokenOptions: options,
identityClient: this.isAvailableIdentityClient,
resourceId: this.resourceId,
});
if (!isAvailable) {
throw new errors_js_1.CredentialUnavailableError(`Attempted to use the IMDS endpoint, but it is not available.`);
}
}
// If we got this far, it means:
// - This is not a tokenExchangeMsi,
// - We already probed for IMDS endpoint availability and failed-fast if it's unreachable.
// We can proceed normally by calling MSAL for a token.
logger.getToken.info("Calling into MSAL for managed identity token.");
const token = await this.managedIdentityApp.acquireToken({
resource,
});
this.ensureValidMsalToken(scopes, token, options);
logger.getToken.info((0, logging_js_1.formatSuccess)(scopes));
return {
expiresOnTimestamp: token.expiresOn.getTime(),
token: token.accessToken,
refreshAfterTimestamp: (_a = token.refreshOn) === null || _a === void 0 ? void 0 : _a.getTime(),
tokenType: "Bearer",
};
}
catch (err) {
logger.getToken.error((0, logging_js_1.formatError)(scopes, err));
// AuthenticationRequiredError described as Error to enforce authentication after trying to retrieve a token silently.
// TODO: why would this _ever_ happen considering we're not trying the silent request in this flow?
if (err.name === "AuthenticationRequiredError") {
throw err;
}
if (isNetworkError(err)) {
throw new errors_js_1.CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err });
}
throw new errors_js_1.CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err });
}
});
}
/**
* Ensures the validity of the MSAL token
*/
ensureValidMsalToken(scopes, msalToken, getTokenOptions) {
const createError = (message) => {
logger.getToken.info(message);
return new errors_js_1.AuthenticationRequiredError({
scopes: Array.isArray(scopes) ? scopes : [scopes],
getTokenOptions,
message,
});
};
if (!msalToken) {
throw createError("No response.");
}
if (!msalToken.expiresOn) {
throw createError(`Response had no "expiresOn" property.`);
}
if (!msalToken.accessToken) {
throw createError(`Response had no "accessToken" property.`);
}
}
}
exports.ManagedIdentityCredential = ManagedIdentityCredential;
function isNetworkError(err) {
// MSAL error
if (err.errorCode === "network_error") {
return true;
}
// Probe errors
if (err.code === "ENETUNREACH" || err.code === "EHOSTUNREACH") {
return true;
}
// This is a special case for Docker Desktop which responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network" or "A socket operation was attempted to an unreachable host"
// rather than just timing out, as expected.
if (err.statusCode === 403 || err.code === 403) {
if (err.message.includes("unreachable")) {
return true;
}
}
return false;
}
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,24 @@
import type { AccessToken } from "@azure/core-auth";
import type { IdentityClient } from "../../client/identityClient.js";
/**
* @internal
*/
export interface MSIConfiguration {
retryConfig: {
maxRetries: number;
startDelayInMs: number;
intervalIncrement: number;
};
identityClient: IdentityClient;
scopes: string | string[];
clientId?: string;
resourceId?: string;
}
/**
* @internal
* Represents an access token for {@link ManagedIdentity} for internal usage,
* with an expiration time and the time in which token should refresh.
*/
export declare interface MSIToken extends AccessToken {
}
//# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/models.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,WAAW,QAAS,SAAQ,WAAW;CAAG"}
@@ -0,0 +1,5 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/models.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken } from \"@azure/core-auth\";\n\nimport type { IdentityClient } from \"../../client/identityClient.js\";\n\n/**\n * @internal\n */\nexport interface MSIConfiguration {\n retryConfig: {\n maxRetries: number;\n startDelayInMs: number;\n intervalIncrement: number;\n };\n identityClient: IdentityClient;\n scopes: string | string[];\n clientId?: string;\n resourceId?: string;\n}\n\n/**\n * @internal\n * Represents an access token for {@link ManagedIdentity} for internal usage,\n * with an expiration time and the time in which token should refresh.\n */\nexport declare interface MSIToken extends AccessToken {}\n"]}
@@ -0,0 +1,37 @@
import type { TokenCredentialOptions } from "../../tokenCredentialOptions.js";
/**
* Options to send on the {@link ManagedIdentityCredential} constructor.
* This variation supports `clientId` and not `resourceId`, since only one of both is supported.
*/
export interface ManagedIdentityCredentialClientIdOptions extends TokenCredentialOptions {
/**
* The client ID of the user - assigned identity, or app registration(when working with AKS pod - identity).
*/
clientId?: string;
}
/**
* Options to send on the {@link ManagedIdentityCredential} constructor.
* This variation supports `resourceId` and not `clientId`, since only one of both is supported.
*/
export interface ManagedIdentityCredentialResourceIdOptions extends TokenCredentialOptions {
/**
* Allows specifying a custom resource Id.
* In scenarios such as when user assigned identities are created using an ARM template,
* where the resource Id of the identity is known but the client Id can't be known ahead of time,
* this parameter allows programs to use these user assigned identities
* without having to first determine the client Id of the created identity.
*/
resourceId: string;
}
/**
* Options to send on the {@link ManagedIdentityCredential} constructor.
* This variation supports `objectId` as a constructor argument.
*/
export interface ManagedIdentityCredentialObjectIdOptions extends TokenCredentialOptions {
/**
* Allows specifying the object ID of the underlying service principal used to authenticate a user-assigned managed identity.
* This is an alternative to providing a client ID or resource ID and is not required for system-assigned managed identities.
*/
objectId: string;
}
//# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/options.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,wCAAyC,SAAQ,sBAAsB;IACtF;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,0CAA2C,SAAQ,sBAAsB;IACxF;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,wCAAyC,SAAQ,sBAAsB;IACtF;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,5 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/options.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { TokenCredentialOptions } from \"../../tokenCredentialOptions.js\";\n\n/**\n * Options to send on the {@link ManagedIdentityCredential} constructor.\n * This variation supports `clientId` and not `resourceId`, since only one of both is supported.\n */\nexport interface ManagedIdentityCredentialClientIdOptions extends TokenCredentialOptions {\n /**\n * The client ID of the user - assigned identity, or app registration(when working with AKS pod - identity).\n */\n clientId?: string;\n}\n\n/**\n * Options to send on the {@link ManagedIdentityCredential} constructor.\n * This variation supports `resourceId` and not `clientId`, since only one of both is supported.\n */\nexport interface ManagedIdentityCredentialResourceIdOptions extends TokenCredentialOptions {\n /**\n * Allows specifying a custom resource Id.\n * In scenarios such as when user assigned identities are created using an ARM template,\n * where the resource Id of the identity is known but the client Id can't be known ahead of time,\n * this parameter allows programs to use these user assigned identities\n * without having to first determine the client Id of the created identity.\n */\n resourceId: string;\n}\n\n/**\n * Options to send on the {@link ManagedIdentityCredential} constructor.\n * This variation supports `objectId` as a constructor argument.\n */\nexport interface ManagedIdentityCredentialObjectIdOptions extends TokenCredentialOptions {\n /**\n * Allows specifying the object ID of the underlying service principal used to authenticate a user-assigned managed identity.\n * This is an alternative to providing a client ID or resource ID and is not required for system-assigned managed identities.\n */\n objectId: string;\n}\n"]}
@@ -0,0 +1,14 @@
import type { AccessToken, GetTokenOptions } from "@azure/core-auth";
import type { MSIConfiguration } from "./models.js";
/**
* Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.
*
* Token exchange MSI (used by AKS) is the only MSI implementation handled entirely by Azure Identity.
* The rest have been migrated to MSAL.
*/
export declare const tokenExchangeMsi: {
name: string;
isAvailable(clientId?: string): Promise<boolean>;
getToken(configuration: MSIConfiguration, getTokenOptions?: GetTokenOptions): Promise<AccessToken | null>;
};
//# sourceMappingURL=tokenExchangeMsi.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"tokenExchangeMsi.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/tokenExchangeMsi.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQpD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;2BAEE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;4BAerC,gBAAgB,oBACd,eAAe,GAC/B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CAY/B,CAAC"}
@@ -0,0 +1,35 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.tokenExchangeMsi = void 0;
const workloadIdentityCredential_js_1 = require("../workloadIdentityCredential.js");
const logging_js_1 = require("../../util/logging.js");
const msiName = "ManagedIdentityCredential - Token Exchange";
const logger = (0, logging_js_1.credentialLogger)(msiName);
/**
* Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.
*
* Token exchange MSI (used by AKS) is the only MSI implementation handled entirely by Azure Identity.
* The rest have been migrated to MSAL.
*/
exports.tokenExchangeMsi = {
name: "tokenExchangeMsi",
async isAvailable(clientId) {
const env = process.env;
const result = Boolean((clientId || env.AZURE_CLIENT_ID) &&
env.AZURE_TENANT_ID &&
process.env.AZURE_FEDERATED_TOKEN_FILE);
if (!result) {
logger.info(`${msiName}: Unavailable. The environment variables needed are: AZURE_CLIENT_ID (or the client ID sent through the parameters), AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE`);
}
return result;
},
async getToken(configuration, getTokenOptions = {}) {
const { scopes, clientId } = configuration;
const identityClientTokenCredentialOptions = {};
const workloadIdentityCredential = new workloadIdentityCredential_js_1.WorkloadIdentityCredential(Object.assign(Object.assign({ clientId, tenantId: process.env.AZURE_TENANT_ID, tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE }, identityClientTokenCredentialOptions), { disableInstanceDiscovery: true }));
return workloadIdentityCredential.getToken(scopes, getTokenOptions);
},
};
//# sourceMappingURL=tokenExchangeMsi.js.map
@@ -0,0 +1 @@
{"version":3,"file":"tokenExchangeMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/tokenExchangeMsi.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;AAIlC,oFAA8E;AAC9E,sDAAyD;AAGzD,MAAM,OAAO,GAAG,4CAA4C,CAAC;AAC7D,MAAM,MAAM,GAAG,IAAA,6BAAgB,EAAC,OAAO,CAAC,CAAC;AAEzC;;;;;GAKG;AACU,QAAA,gBAAgB,GAAG;IAC9B,IAAI,EAAE,kBAAkB;IACxB,KAAK,CAAC,WAAW,CAAC,QAAiB;QACjC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACxB,MAAM,MAAM,GAAG,OAAO,CACpB,CAAC,QAAQ,IAAI,GAAG,CAAC,eAAe,CAAC;YAC/B,GAAG,CAAC,eAAe;YACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CACzC,CAAC;QACF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,qKAAqK,CAChL,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,aAA+B,EAC/B,kBAAmC,EAAE;QAErC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;QAC3C,MAAM,oCAAoC,GAAG,EAAE,CAAC;QAChD,MAAM,0BAA0B,GAAG,IAAI,0DAA0B,CAAC,8BAChE,QAAQ,EACR,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,EACrC,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAClD,oCAAoC,KACvC,wBAAwB,EAAE,IAAI,GACM,CAAC,CAAC;QACxC,OAAO,0BAA0B,CAAC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACtE,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport type { MSIConfiguration } from \"./models.js\";\nimport { WorkloadIdentityCredential } from \"../workloadIdentityCredential.js\";\nimport { credentialLogger } from \"../../util/logging.js\";\nimport type { WorkloadIdentityCredentialOptions } from \"../workloadIdentityCredentialOptions.js\";\n\nconst msiName = \"ManagedIdentityCredential - Token Exchange\";\nconst logger = credentialLogger(msiName);\n\n/**\n * Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI.\n *\n * Token exchange MSI (used by AKS) is the only MSI implementation handled entirely by Azure Identity.\n * The rest have been migrated to MSAL.\n */\nexport const tokenExchangeMsi = {\n name: \"tokenExchangeMsi\",\n async isAvailable(clientId?: string): Promise<boolean> {\n const env = process.env;\n const result = Boolean(\n (clientId || env.AZURE_CLIENT_ID) &&\n env.AZURE_TENANT_ID &&\n process.env.AZURE_FEDERATED_TOKEN_FILE,\n );\n if (!result) {\n logger.info(\n `${msiName}: Unavailable. The environment variables needed are: AZURE_CLIENT_ID (or the client ID sent through the parameters), AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE`,\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {},\n ): Promise<AccessToken | null> {\n const { scopes, clientId } = configuration;\n const identityClientTokenCredentialOptions = {};\n const workloadIdentityCredential = new WorkloadIdentityCredential({\n clientId,\n tenantId: process.env.AZURE_TENANT_ID,\n tokenFilePath: process.env.AZURE_FEDERATED_TOKEN_FILE,\n ...identityClientTokenCredentialOptions,\n disableInstanceDiscovery: true,\n } as WorkloadIdentityCredentialOptions);\n return workloadIdentityCredential.getToken(scopes, getTokenOptions);\n },\n};\n"]}
@@ -0,0 +1,37 @@
/**
* Error message for Service Fabric Managed Identity environment.
*/
export declare const serviceFabricErrorMessage = "Specifying a `clientId` or `resourceId` is not supported by the Service Fabric managed identity environment. The managed identity configuration is determined by the Service Fabric cluster resource configuration. See https://aka.ms/servicefabricmi for more information";
/**
* 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.
* This resource can be derived from the scopes received through the getToken call, as long as only one scope is received.
* Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case.
*
* For that reason, when we encounter multiple scopes, we return undefined.
* It's up to the individual MSI implementations to throw the errors (which helps us provide less generic errors).
*/
export declare function mapScopesToResource(scopes: string | string[]): string | undefined;
/**
* Internal type roughly matching the raw responses of the authentication endpoints.
*
* @internal
*/
export interface TokenResponseParsedBody {
access_token?: string;
refresh_token?: string;
expires_in: number;
expires_on?: number | string;
refresh_on?: number | string;
}
/**
* Given a token response, return the expiration timestamp as the number of milliseconds from the Unix epoch.
* @param body - A parsed response body from the authentication endpoint.
*/
export declare function parseExpirationTimestamp(body: TokenResponseParsedBody): number;
/**
* Given a token response, return the expiration timestamp as the number of milliseconds from the Unix epoch.
* @param body - A parsed response body from the authentication endpoint.
*/
export declare function parseRefreshTimestamp(body: TokenResponseParsedBody): number | undefined;
//# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,eAAO,MAAM,yBAAyB,gRACyO,CAAC;AAEhR;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAiBjF;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAwB9E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAqBvF"}
@@ -0,0 +1,87 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.serviceFabricErrorMessage = void 0;
exports.mapScopesToResource = mapScopesToResource;
exports.parseExpirationTimestamp = parseExpirationTimestamp;
exports.parseRefreshTimestamp = parseRefreshTimestamp;
const DefaultScopeSuffix = "/.default";
/**
* Error message for Service Fabric Managed Identity environment.
*/
exports.serviceFabricErrorMessage = "Specifying a `clientId` or `resourceId` is not supported by the Service Fabric managed identity environment. The managed identity configuration is determined by the Service Fabric cluster resource configuration. See https://aka.ms/servicefabricmi for more information";
/**
* 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.
* This resource can be derived from the scopes received through the getToken call, as long as only one scope is received.
* Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case.
*
* For that reason, when we encounter multiple scopes, we return undefined.
* It's up to the individual MSI implementations to throw the errors (which helps us provide less generic errors).
*/
function mapScopesToResource(scopes) {
let scope = "";
if (Array.isArray(scopes)) {
if (scopes.length !== 1) {
return;
}
scope = scopes[0];
}
else if (typeof scopes === "string") {
scope = scopes;
}
if (!scope.endsWith(DefaultScopeSuffix)) {
return scope;
}
return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix));
}
/**
* Given a token response, return the expiration timestamp as the number of milliseconds from the Unix epoch.
* @param body - A parsed response body from the authentication endpoint.
*/
function parseExpirationTimestamp(body) {
if (typeof body.expires_on === "number") {
return body.expires_on * 1000;
}
if (typeof body.expires_on === "string") {
const asNumber = +body.expires_on;
if (!isNaN(asNumber)) {
return asNumber * 1000;
}
const asDate = Date.parse(body.expires_on);
if (!isNaN(asDate)) {
return asDate;
}
}
if (typeof body.expires_in === "number") {
return Date.now() + body.expires_in * 1000;
}
throw new Error(`Failed to parse token expiration from body. expires_in="${body.expires_in}", expires_on="${body.expires_on}"`);
}
/**
* Given a token response, return the expiration timestamp as the number of milliseconds from the Unix epoch.
* @param body - A parsed response body from the authentication endpoint.
*/
function parseRefreshTimestamp(body) {
if (body.refresh_on) {
if (typeof body.refresh_on === "number") {
return body.refresh_on * 1000;
}
if (typeof body.refresh_on === "string") {
const asNumber = +body.refresh_on;
if (!isNaN(asNumber)) {
return asNumber * 1000;
}
const asDate = Date.parse(body.refresh_on);
if (!isNaN(asDate)) {
return asDate;
}
}
throw new Error(`Failed to parse refresh_on from body. refresh_on="${body.refresh_on}"`);
}
else {
return undefined;
}
}
//# sourceMappingURL=utils.js.map
File diff suppressed because one or more lines are too long