@azure/msal-browser
Version:
Microsoft Authentication Library for js
269 lines (252 loc) • 10.6 kB
text/typescript
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import {
ICrypto,
INetworkModule,
Logger,
AccountInfo,
UrlString,
ServerTelemetryManager,
ServerTelemetryRequest,
createClientConfigurationError,
ClientConfigurationErrorCodes,
Authority,
AuthorityOptions,
AuthorityFactory,
IPerformanceClient,
AzureCloudOptions,
invokeAsync,
StringDict,
} from "@azure/msal-common/browser";
import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js";
import { BrowserConfiguration } from "../config/Configuration.js";
import { BrowserCacheManager } from "../cache/BrowserCacheManager.js";
import { EventHandler } from "../event/EventHandler.js";
import { EndSessionRequest } from "../request/EndSessionRequest.js";
import { RedirectRequest } from "../request/RedirectRequest.js";
import { PopupRequest } from "../request/PopupRequest.js";
import { SsoSilentRequest } from "../request/SsoSilentRequest.js";
import { version } from "../packageMetadata.js";
import { BrowserConstants } from "../utils/BrowserConstants.js";
import * as BrowserUtils from "../utils/BrowserUtils.js";
import { INavigationClient } from "../navigation/INavigationClient.js";
import { AuthenticationResult } from "../response/AuthenticationResult.js";
import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js";
export abstract class BaseInteractionClient {
protected config: BrowserConfiguration;
protected browserStorage: BrowserCacheManager;
protected browserCrypto: ICrypto;
protected networkClient: INetworkModule;
protected logger: Logger;
protected eventHandler: EventHandler;
protected navigationClient: INavigationClient;
protected platformAuthProvider: IPlatformAuthHandler | undefined;
protected correlationId: string;
protected performanceClient: IPerformanceClient;
constructor(
config: BrowserConfiguration,
storageImpl: BrowserCacheManager,
browserCrypto: ICrypto,
logger: Logger,
eventHandler: EventHandler,
navigationClient: INavigationClient,
performanceClient: IPerformanceClient,
correlationId: string,
platformAuthProvider?: IPlatformAuthHandler
) {
this.config = config;
this.browserStorage = storageImpl;
this.browserCrypto = browserCrypto;
this.networkClient = this.config.system.networkClient;
this.eventHandler = eventHandler;
this.navigationClient = navigationClient;
this.platformAuthProvider = platformAuthProvider;
this.correlationId = correlationId;
this.logger = logger.clone(BrowserConstants.MSAL_SKU, version);
this.performanceClient = performanceClient;
}
abstract acquireToken(
request: RedirectRequest | PopupRequest | SsoSilentRequest
): Promise<AuthenticationResult | void>;
abstract logout(
request: EndSessionRequest | ClearCacheRequest | undefined
): Promise<void>;
}
/**
* Use to get the redirect URI configured in MSAL or construct one from the current page.
* @param requestRedirectUri - Redirect URI from the request or undefined if not configured
* @param clientConfigRedirectUri - Redirect URI from the client configuration or undefined if not configured
* @param logger - Logger instance from the calling client
* @param correlationId
* @returns Absolute redirect URL constructed from the provided URI, config, or current page
*/
export function getRedirectUri(
requestRedirectUri: string | undefined,
clientConfigRedirectUri: string | undefined,
logger: Logger,
correlationId: string
): string {
logger.verbose("getRedirectUri called", correlationId);
const redirectUri = requestRedirectUri || clientConfigRedirectUri || "";
return UrlString.getAbsoluteUrl(redirectUri, BrowserUtils.getCurrentUri());
}
/**
* Initializes and returns a ServerTelemetryManager with the provided telemetry configuration.
* @param apiId - The API identifier for telemetry tracking
* @param clientId - The client application identifier
* @param correlationId - Unique identifier for correlating requests
* @param browserStorage - Browser cache manager instance for storing telemetry data
* @param logger - Optional logger instance for verbose logging
* @param forceRefresh - Optional flag to force refresh of telemetry data
* @returns Configured ServerTelemetryManager instance
*/
export function initializeServerTelemetryManager(
apiId: number,
clientId: string,
correlationId: string,
browserStorage: BrowserCacheManager,
logger: Logger,
forceRefresh?: boolean
): ServerTelemetryManager {
logger.verbose("initializeServerTelemetryManager called", correlationId);
const telemetryPayload: ServerTelemetryRequest = {
clientId: clientId,
correlationId: correlationId,
apiId: apiId,
forceRefresh: forceRefresh || false,
wrapperSKU: browserStorage.getWrapperMetadata()[0],
wrapperVer: browserStorage.getWrapperMetadata()[1],
};
return new ServerTelemetryManager(telemetryPayload, browserStorage);
}
/**
* Used to get a discovered version of the default authority.
* @param params - Configuration object containing authority and cloud options
* @param params.requestAuthority - Optional specific authority URL to use
* @param params.requestAzureCloudOptions - Optional Azure cloud configuration options
* @param params.requestExtraQueryParameters - Optional additional query parameters
* @param params.account - Optional account info for instance-aware scenarios
* @param config - Browser configuration containing auth settings
* @param correlationId - Unique identifier for correlating requests
* @param performanceClient - Performance monitoring client instance
* @param browserStorage - Browser cache manager instance
* @param logger - Logger instance for tracking operations
* @returns Promise that resolves to a discovered Authority instance
*/
export async function getDiscoveredAuthority(
config: BrowserConfiguration,
correlationId: string,
performanceClient: IPerformanceClient,
browserStorage: BrowserCacheManager,
logger: Logger,
requestAuthority?: string,
requestAzureCloudOptions?: AzureCloudOptions,
requestExtraQueryParameters?: StringDict,
account?: AccountInfo
): Promise<Authority> {
const instanceAwareEQ =
requestExtraQueryParameters &&
requestExtraQueryParameters.hasOwnProperty("instance_aware")
? requestExtraQueryParameters["instance_aware"]
: undefined;
const authorityOptions: AuthorityOptions = {
protocolMode: config.system.protocolMode,
OIDCOptions: config.auth.OIDCOptions,
knownAuthorities: config.auth.knownAuthorities,
cloudDiscoveryMetadata: config.auth.cloudDiscoveryMetadata,
authorityMetadata: config.auth.authorityMetadata,
};
// build authority string based on auth params, precedence - azureCloudInstance + tenant >> authority
const resolvedAuthority = requestAuthority || config.auth.authority;
const resolvedInstanceAware = instanceAwareEQ?.length
? instanceAwareEQ === "true"
: config.auth.instanceAware;
const userAuthority =
account && resolvedInstanceAware
? config.auth.authority.replace(
UrlString.getDomainFromUrl(resolvedAuthority),
account.environment
)
: resolvedAuthority;
// fall back to the authority from config
const builtAuthority = Authority.generateAuthority(
userAuthority,
requestAzureCloudOptions || config.auth.azureCloudOptions
);
const discoveredAuthority = await invokeAsync(
AuthorityFactory.createDiscoveredInstance,
BrowserPerformanceEvents.AuthorityFactoryCreateDiscoveredInstance,
logger,
performanceClient,
correlationId
)(
builtAuthority,
config.system.networkClient,
browserStorage,
authorityOptions,
logger,
correlationId,
performanceClient
);
if (account && !discoveredAuthority.isAlias(account.environment)) {
throw createClientConfigurationError(
ClientConfigurationErrorCodes.authorityMismatch
);
}
return discoveredAuthority;
}
/**
* Clears cache and account information during logout.
*
* If an account is provided, removes the account from cache and, if it is the active account, sets the active account to null.
* If no account is provided, clears all accounts and tokens from cache.
*
* @param browserStorage - The browser cache manager instance used to manage cache.
* @param browserCrypto - The crypto interface for cache operations.
* @param logger - Logger instance for logging operations.
* @param correlationId - Correlation ID for the logout operation.
* @param account - (Optional) The account to clear from cache. If not provided, all accounts are cleared.
* @returns A promise that resolves when the cache has been cleared.
*/
export async function clearCacheOnLogout(
browserStorage: BrowserCacheManager,
browserCrypto: ICrypto,
logger: Logger,
correlationId: string,
account?: AccountInfo | null
): Promise<void> {
if (account) {
// Clear given account.
try {
browserStorage.removeAccount(account, correlationId);
logger.verbose(
"Cleared cache items belonging to the account provided in the logout request.",
correlationId
);
} catch (error) {
logger.error(
"Account provided in logout request was not found. Local cache unchanged.",
correlationId
);
}
} else {
try {
logger.verbose(
"No account provided in logout request, clearing all cache items.",
correlationId
);
// Clear all accounts and tokens
browserStorage.clear(correlationId);
// Clear any stray keys from IndexedDB
await browserCrypto.clearKeystore(correlationId);
} catch (e) {
logger.error(
"Attempted to clear all MSAL cache items and failed. Local cache unchanged.",
correlationId
);
}
}
}