UNPKG

@azure/msal-browser

Version:
219 lines (216 loc) 11.6 kB
/*! @azure/msal-browser v5.6.3 2026-04-01 */ 'use strict'; import { StubPerformanceClient, AuthToken, Logger, buildStaticAuthorityOptions, AuthorityFactory, Authority, invokeAsync, AccountEntityUtils, buildAccountToCache, CacheHelpers, ScopeSet, TimeUtils } from '@azure/msal-common/browser'; import { buildConfiguration } from '../config/Configuration.mjs'; import { createNewGuid } from '../crypto/BrowserCrypto.mjs'; import { CryptoOps } from '../crypto/CryptoOps.mjs'; import { base64Decode } from '../encode/Base64Decode.mjs'; import { createBrowserAuthError } from '../error/BrowserAuthError.mjs'; import { EventHandler } from '../event/EventHandler.mjs'; import { LoadAccount, LoadIdToken, LoadAccessToken, LoadRefreshToken } from '../telemetry/BrowserPerformanceEvents.mjs'; import { LoadExternalTokens } from '../telemetry/BrowserRootPerformanceEvents.mjs'; import { ApiId } from '../utils/BrowserConstants.mjs'; import { blockNonBrowserEnvironment } from '../utils/BrowserUtils.mjs'; import { BrowserCacheManager } from './BrowserCacheManager.mjs'; import { unableToLoadToken } from '../error/BrowserAuthErrorCodes.mjs'; /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * API to load tokens to msal-browser cache. * @param config - Object to configure the MSAL app. * @param request - Silent request containing authority, scopes, and account. * @param response - External token response to load into the cache. * @param options - Options controlling how tokens are loaded into the cache. * @param performanceClient - Optional performance client used for telemetry measurements. * @returns `AuthenticationResult` for the response that was loaded. */ async function loadExternalTokens(config, request, response, options, performanceClient = new StubPerformanceClient()) { blockNonBrowserEnvironment(); const browserConfig = buildConfiguration(config, true); const correlationId = request.correlationId || createNewGuid(); const rootMeasurement = performanceClient.startMeasurement(LoadExternalTokens, correlationId); try { const idTokenClaims = response.id_token ? AuthToken.extractTokenClaims(response.id_token, base64Decode) : undefined; const kmsi = AuthToken.isKmsi(idTokenClaims || {}); const authorityOptions = { protocolMode: browserConfig.system.protocolMode, knownAuthorities: browserConfig.auth.knownAuthorities, cloudDiscoveryMetadata: browserConfig.auth.cloudDiscoveryMetadata, authorityMetadata: browserConfig.auth.authorityMetadata, }; const logger = new Logger(browserConfig.system.loggerOptions || {}); const cryptoOps = new CryptoOps(logger, browserConfig.telemetry.client); const storage = new BrowserCacheManager(browserConfig.auth.clientId, browserConfig.cache, cryptoOps, logger, browserConfig.telemetry.client, new EventHandler(logger), buildStaticAuthorityOptions(browserConfig.auth)); const authorityString = request.authority || browserConfig.auth.authority; const authority = await AuthorityFactory.createDiscoveredInstance(Authority.generateAuthority(authorityString, request.azureCloudOptions), browserConfig.system.networkClient, storage, authorityOptions, logger, correlationId, performanceClient); const cacheRecordAccount = await invokeAsync(loadAccount, LoadAccount, logger, performanceClient, correlationId)(request, options.clientInfo || response.client_info || "", correlationId, storage, logger, cryptoOps, authority, idTokenClaims, performanceClient); const idToken = await invokeAsync(loadIdToken, LoadIdToken, logger, performanceClient, correlationId)(response, cacheRecordAccount.homeAccountId, cacheRecordAccount.environment, cacheRecordAccount.realm, kmsi, correlationId, storage, logger, config.auth.clientId); const accessToken = await invokeAsync(loadAccessToken, LoadAccessToken, logger, performanceClient, correlationId)(request, response, cacheRecordAccount.homeAccountId, cacheRecordAccount.environment, cacheRecordAccount.realm, kmsi, options, correlationId, storage, logger, config.auth.clientId); const refreshToken = await invokeAsync(loadRefreshToken, LoadRefreshToken, logger, performanceClient, correlationId)(response, cacheRecordAccount.homeAccountId, cacheRecordAccount.environment, kmsi, correlationId, storage, logger, config.auth.clientId, performanceClient); rootMeasurement.end({ success: true }, undefined, AccountEntityUtils.getAccountInfo(cacheRecordAccount)); return generateAuthenticationResult(request, { account: cacheRecordAccount, idToken, accessToken, refreshToken, }, authority, idTokenClaims); } catch (error) { rootMeasurement.end({ success: false }, error); throw error; } } /** * Helper function to load account to msal-browser cache * @param idToken * @param environment * @param clientInfo * @param authorityType * @param requestHomeAccountId * @returns `AccountEntity` */ async function loadAccount(request, clientInfo, correlationId, storage, logger, cryptoObj, authority, idTokenClaims, performanceClient) { logger.verbose("0ke46k", correlationId); if (request.account) { const accountEntity = AccountEntityUtils.createAccountEntityFromAccountInfo(request.account); await storage.setAccount(accountEntity, correlationId, AuthToken.isKmsi(idTokenClaims || {}), ApiId.loadExternalTokens); return accountEntity; } else if (!clientInfo && !idTokenClaims) { logger.error("0hzcn4", correlationId); throw createBrowserAuthError(unableToLoadToken); } const homeAccountId = AccountEntityUtils.generateHomeAccountId(clientInfo, authority.authorityType, logger, cryptoObj, correlationId, idTokenClaims); const claimsTenantId = idTokenClaims?.tid; const cachedAccount = buildAccountToCache(storage, authority, homeAccountId, base64Decode, correlationId, idTokenClaims, clientInfo, authority.getPreferredCache(), claimsTenantId, undefined, // authCodePayload undefined, // nativeAccountId logger, performanceClient); await storage.setAccount(cachedAccount, correlationId, AuthToken.isKmsi(idTokenClaims || {}), ApiId.loadExternalTokens); return cachedAccount; } /** * Helper function to load id tokens to msal-browser cache * @param idToken * @param homeAccountId * @param environment * @param tenantId * @returns `IdTokenEntity` */ async function loadIdToken(response, homeAccountId, environment, tenantId, kmsi, correlationId, storage, logger, clientId) { if (!response.id_token) { logger.verbose("1pm7g1", correlationId); return null; } logger.verbose("168lyi", correlationId); const idTokenEntity = CacheHelpers.createIdTokenEntity(homeAccountId, environment, response.id_token, clientId, tenantId); await storage.setIdTokenCredential(idTokenEntity, correlationId, kmsi); return idTokenEntity; } /** * Helper function to load access tokens to msal-browser cache * @param request * @param response * @param homeAccountId * @param environment * @param tenantId * @returns `AccessTokenEntity` */ async function loadAccessToken(request, response, homeAccountId, environment, tenantId, kmsi, options, correlationId, storage, logger, clientId) { if (!response.access_token) { logger.verbose("1ckp9e", correlationId); return null; } else if (!response.expires_in) { logger.error("15mzx8", correlationId); return null; } else if (!response.scope && (!request.scopes || !request.scopes.length)) { logger.error("1h7xse", correlationId); return null; } logger.verbose("01kmxb", correlationId); const scopes = response.scope ? ScopeSet.fromString(response.scope) : new ScopeSet(request.scopes); const expiresOn = options.expiresOn || response.expires_in + TimeUtils.nowSeconds(); const extendedExpiresOn = options.extendedExpiresOn || (response.ext_expires_in || response.expires_in) + TimeUtils.nowSeconds(); const accessTokenEntity = CacheHelpers.createAccessTokenEntity(homeAccountId, environment, response.access_token, clientId, tenantId, scopes.printScopes(), expiresOn, extendedExpiresOn, base64Decode); await storage.setAccessTokenCredential(accessTokenEntity, correlationId, kmsi); return accessTokenEntity; } /** * Helper function to load refresh tokens to msal-browser cache * @param request * @param response * @param homeAccountId * @param environment * @returns `RefreshTokenEntity` */ async function loadRefreshToken(response, homeAccountId, environment, kmsi, correlationId, storage, logger, clientId, performanceClient) { if (!response.refresh_token) { logger.verbose("1l7um5", correlationId); return null; } const expiresOn = response.refresh_token_expires_in ? response.refresh_token_expires_in + TimeUtils.nowSeconds() : undefined; performanceClient.addFields({ extRtExpiresOnSeconds: expiresOn, }, correlationId); logger.verbose("0qy8ev", correlationId); const refreshTokenEntity = CacheHelpers.createRefreshTokenEntity(homeAccountId, environment, response.refresh_token, clientId, response.foci, undefined, // userAssertionHash expiresOn); await storage.setRefreshTokenCredential(refreshTokenEntity, correlationId, kmsi); return refreshTokenEntity; } /** * Helper function to generate an `AuthenticationResult` for the result. * @param request * @param idTokenObj * @param cacheRecord * @param authority * @returns `AuthenticationResult` */ function generateAuthenticationResult(request, cacheRecord, authority, idTokenClaims) { let accessToken = ""; let responseScopes = []; let expiresOn = null; let extExpiresOn; if (cacheRecord?.accessToken) { accessToken = cacheRecord.accessToken.secret; responseScopes = ScopeSet.fromString(cacheRecord.accessToken.target).asArray(); // Access token expiresOn stored in seconds, converting to Date for AuthenticationResult expiresOn = TimeUtils.toDateFromSeconds(cacheRecord.accessToken.expiresOn); extExpiresOn = TimeUtils.toDateFromSeconds(cacheRecord.accessToken.extendedExpiresOn); } const accountEntity = cacheRecord.account; return { authority: authority.canonicalAuthority, uniqueId: cacheRecord.account.localAccountId, tenantId: cacheRecord.account.realm, scopes: responseScopes, account: AccountEntityUtils.getAccountInfo(accountEntity), idToken: cacheRecord.idToken?.secret || "", idTokenClaims: idTokenClaims || {}, accessToken: accessToken, fromCache: true, expiresOn: expiresOn, correlationId: request.correlationId || "", requestId: "", extExpiresOn: extExpiresOn, familyId: cacheRecord.refreshToken?.familyId || "", tokenType: cacheRecord?.accessToken?.tokenType || "", state: request.state || "", cloudGraphHostName: accountEntity.cloudGraphHostName || "", msGraphHost: accountEntity.msGraphHost || "", fromPlatformBroker: false, }; } export { loadExternalTokens }; //# sourceMappingURL=TokenCache.mjs.map