/*! @azure/msal-browser v5.9.0 2026-04-28 */
'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
