LookAtMySuitBot/js/node_modules/@azure/msal-common/dist/client/SilentFlowClient.mjs

136 lines
6.8 KiB
JavaScript

/*! @azure/msal-common v14.4.0 2023-11-07 */
'use strict';
import { BaseClient } from './BaseClient.mjs';
import { TimeUtils } from '../utils/TimeUtils.mjs';
import { RefreshTokenClient } from './RefreshTokenClient.mjs';
import { ClientAuthError, createClientAuthError } from '../error/ClientAuthError.mjs';
import { ResponseHandler } from '../response/ResponseHandler.mjs';
import { CacheOutcome } from '../utils/Constants.mjs';
import { StringUtils } from '../utils/StringUtils.mjs';
import { extractTokenClaims, checkMaxAge } from '../account/AuthToken.mjs';
import { PerformanceEvents } from '../telemetry/performance/PerformanceEvent.mjs';
import { invokeAsync } from '../utils/FunctionWrappers.mjs';
import { tokenRefreshRequired, noAccountInSilentRequest, authTimeNotFound } from '../error/ClientAuthErrorCodes.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/** @internal */
class SilentFlowClient extends BaseClient {
constructor(configuration, performanceClient) {
super(configuration, performanceClient);
}
/**
* Retrieves a token from cache if it is still valid, or uses the cached refresh token to renew
* the given token and returns the renewed token
* @param request
*/
async acquireToken(request) {
try {
const [authResponse, cacheOutcome] = await this.acquireCachedToken(request);
// if the token is not expired but must be refreshed; get a new one in the background
if (cacheOutcome === CacheOutcome.PROACTIVELY_REFRESHED) {
this.logger.info("SilentFlowClient:acquireCachedToken - Cached access token's refreshOn property has been exceeded'. It's not expired, but must be refreshed.");
// refresh the access token in the background
const refreshTokenClient = new RefreshTokenClient(this.config, this.performanceClient);
refreshTokenClient
.acquireTokenByRefreshToken(request)
.catch(() => {
// do nothing, this is running in the background and no action is to be taken upon success or failure
});
}
// return the cached token
return authResponse;
}
catch (e) {
if (e instanceof ClientAuthError &&
e.errorCode === tokenRefreshRequired) {
const refreshTokenClient = new RefreshTokenClient(this.config, this.performanceClient);
return refreshTokenClient.acquireTokenByRefreshToken(request);
}
else {
throw e;
}
}
}
/**
* Retrieves token from cache or throws an error if it must be refreshed.
* @param request
*/
async acquireCachedToken(request) {
this.performanceClient?.addQueueMeasurement(PerformanceEvents.SilentFlowClientAcquireCachedToken, request.correlationId);
let lastCacheOutcome = CacheOutcome.NOT_APPLICABLE;
if (request.forceRefresh ||
(!this.config.cacheOptions.claimsBasedCachingEnabled &&
!StringUtils.isEmptyObj(request.claims))) {
// Must refresh due to present force_refresh flag.
this.setCacheOutcome(CacheOutcome.FORCE_REFRESH_OR_CLAIMS, request.correlationId);
throw createClientAuthError(tokenRefreshRequired);
}
// We currently do not support silent flow for account === null use cases; This will be revisited for confidential flow usecases
if (!request.account) {
throw createClientAuthError(noAccountInSilentRequest);
}
const environment = request.authority || this.authority.getPreferredCache();
const cacheRecord = this.cacheManager.readCacheRecord(request.account, request, environment, this.performanceClient, request.correlationId);
if (!cacheRecord.accessToken) {
// must refresh due to non-existent access_token
this.setCacheOutcome(CacheOutcome.NO_CACHED_ACCESS_TOKEN, request.correlationId);
throw createClientAuthError(tokenRefreshRequired);
}
else if (TimeUtils.wasClockTurnedBack(cacheRecord.accessToken.cachedAt) ||
TimeUtils.isTokenExpired(cacheRecord.accessToken.expiresOn, this.config.systemOptions.tokenRenewalOffsetSeconds)) {
// must refresh due to the expires_in value
this.setCacheOutcome(CacheOutcome.CACHED_ACCESS_TOKEN_EXPIRED, request.correlationId);
throw createClientAuthError(tokenRefreshRequired);
}
else if (cacheRecord.accessToken.refreshOn &&
TimeUtils.isTokenExpired(cacheRecord.accessToken.refreshOn, 0)) {
// must refresh (in the background) due to the refresh_in value
lastCacheOutcome = CacheOutcome.PROACTIVELY_REFRESHED;
// don't throw ClientAuthError.createRefreshRequiredError(), return cached token instead
}
this.setCacheOutcome(lastCacheOutcome, request.correlationId);
if (this.config.serverTelemetryManager) {
this.config.serverTelemetryManager.incrementCacheHits();
}
return [
await invokeAsync(this.generateResultFromCacheRecord.bind(this), PerformanceEvents.SilentFlowClientGenerateResultFromCacheRecord, this.logger, this.performanceClient, request.correlationId)(cacheRecord, request),
lastCacheOutcome,
];
}
setCacheOutcome(cacheOutcome, correlationId) {
this.serverTelemetryManager?.setCacheOutcome(cacheOutcome);
this.performanceClient?.addFields({
cacheOutcome: cacheOutcome,
}, correlationId);
if (cacheOutcome !== CacheOutcome.NOT_APPLICABLE) {
this.logger.info(`Token refresh is required due to cache outcome: ${cacheOutcome}`);
}
}
/**
* Helper function to build response object from the CacheRecord
* @param cacheRecord
*/
async generateResultFromCacheRecord(cacheRecord, request) {
this.performanceClient?.addQueueMeasurement(PerformanceEvents.SilentFlowClientGenerateResultFromCacheRecord, request.correlationId);
let idTokenClaims;
if (cacheRecord.idToken) {
idTokenClaims = extractTokenClaims(cacheRecord.idToken.secret, this.config.cryptoInterface.base64Decode);
}
// token max_age check
if (request.maxAge || request.maxAge === 0) {
const authTime = idTokenClaims?.auth_time;
if (!authTime) {
throw createClientAuthError(authTimeNotFound);
}
checkMaxAge(authTime, request.maxAge);
}
return await ResponseHandler.generateAuthenticationResult(this.cryptoUtils, this.authority, cacheRecord, true, request, idTokenClaims);
}
}
export { SilentFlowClient };
//# sourceMappingURL=SilentFlowClient.mjs.map