UNPKG

@azure/msal-browser

Version:
274 lines (271 loc) 18.3 kB
/*! @azure/msal-browser v2.34.0 2023-03-07 */ 'use strict'; import { __extends, __awaiter, __generator, __assign } from '../_virtual/_tslib.js'; import { PerformanceEvents, Constants, ServerError, InteractionRequiredAuthError } from '@azure/msal-common'; import { DEFAULT_REQUEST, InteractionType, CacheLookupPolicy, ApiId, BrowserConstants } from '../utils/BrowserConstants.js'; import { ClientApplication } from './ClientApplication.js'; import { EventType } from '../event/EventType.js'; import { BrowserAuthError } from '../error/BrowserAuthError.js'; import { NativeAuthError } from '../error/NativeAuthError.js'; import { NativeMessageHandler } from '../broker/nativeBroker/NativeMessageHandler.js'; import { BrowserUtils } from '../utils/BrowserUtils.js'; /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * The PublicClientApplication class is the object exposed by the library to perform authentication and authorization functions in Single Page Applications * to obtain JWT tokens as described in the OAuth 2.0 Authorization Code Flow with PKCE specification. */ var PublicClientApplication = /** @class */ (function (_super) { __extends(PublicClientApplication, _super); /** * @constructor * Constructor for the PublicClientApplication used to instantiate the PublicClientApplication object * * Important attributes in the Configuration object for auth are: * - clientID: the application ID of your application. You can obtain one by registering your application with our Application registration portal : https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview * - authority: the authority URL for your application. * - redirect_uri: the uri of your application registered in the portal. * * In Azure AD, authority is a URL indicating the Azure active directory that MSAL uses to obtain tokens. * It is of the form https://login.microsoftonline.com/{Enter_the_Tenant_Info_Here} * If your application supports Accounts in one organizational directory, replace "Enter_the_Tenant_Info_Here" value with the Tenant Id or Tenant name (for example, contoso.microsoft.com). * If your application supports Accounts in any organizational directory, replace "Enter_the_Tenant_Info_Here" value with organizations. * If your application supports Accounts in any organizational directory and personal Microsoft accounts, replace "Enter_the_Tenant_Info_Here" value with common. * To restrict support to Personal Microsoft accounts only, replace "Enter_the_Tenant_Info_Here" value with consumers. * * In Azure B2C, authority is of the form https://{instance}/tfp/{tenant}/{policyName}/ * Full B2C functionality will be available in this library in future versions. * * @param configuration object for the MSAL PublicClientApplication instance */ function PublicClientApplication(configuration) { var _this = _super.call(this, configuration) || this; _this.astsAsyncMeasurement = undefined; _this.activeSilentTokenRequests = new Map(); // Register listener functions _this.trackPageVisibility = _this.trackPageVisibility.bind(_this); return _this; } /** * Use when initiating the login process by redirecting the user's browser to the authorization endpoint. This function redirects the page, so * any code that follows this function will not execute. * * IMPORTANT: It is NOT recommended to have code that is dependent on the resolution of the Promise. This function will navigate away from the current * browser window. It currently returns a Promise in order to reflect the asynchronous nature of the code running in this function. * * @param request */ PublicClientApplication.prototype.loginRedirect = function (request) { return __awaiter(this, void 0, void 0, function () { var correlationId; return __generator(this, function (_a) { correlationId = this.getRequestCorrelationId(request); this.logger.verbose("loginRedirect called", correlationId); return [2 /*return*/, this.acquireTokenRedirect(__assign({ correlationId: correlationId }, (request || DEFAULT_REQUEST)))]; }); }); }; /** * Use when initiating the login process via opening a popup window in the user's browser * * @param request * * @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised. */ PublicClientApplication.prototype.loginPopup = function (request) { var correlationId = this.getRequestCorrelationId(request); this.logger.verbose("loginPopup called", correlationId); return this.acquireTokenPopup(__assign({ correlationId: correlationId }, (request || DEFAULT_REQUEST))); }; /** * Silently acquire an access token for a given set of scopes. Returns currently processing promise if parallel requests are made. * * @param {@link (SilentRequest:type)} * @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object */ PublicClientApplication.prototype.acquireTokenSilent = function (request) { return __awaiter(this, void 0, void 0, function () { var correlationId, atsMeasurement, account, thumbprint, silentRequestKey, cachedResponse, response; var _this = this; return __generator(this, function (_a) { correlationId = this.getRequestCorrelationId(request); atsMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenSilent, correlationId); atsMeasurement.addStaticFields({ cacheLookupPolicy: request.cacheLookupPolicy }); this.preflightBrowserEnvironmentCheck(InteractionType.Silent); this.logger.verbose("acquireTokenSilent called", correlationId); account = request.account || this.getActiveAccount(); if (!account) { throw BrowserAuthError.createNoAccountError(); } thumbprint = { clientId: this.config.auth.clientId, authority: request.authority || Constants.EMPTY_STRING, scopes: request.scopes, homeAccountIdentifier: account.homeAccountId, claims: request.claims, authenticationScheme: request.authenticationScheme, resourceRequestMethod: request.resourceRequestMethod, resourceRequestUri: request.resourceRequestUri, shrClaims: request.shrClaims, sshKid: request.sshKid }; silentRequestKey = JSON.stringify(thumbprint); cachedResponse = this.activeSilentTokenRequests.get(silentRequestKey); if (typeof cachedResponse === "undefined") { this.logger.verbose("acquireTokenSilent called for the first time, storing active request", correlationId); this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenSilentAsync, correlationId); response = this.acquireTokenSilentAsync(__assign(__assign({}, request), { correlationId: correlationId }), account) .then(function (result) { _this.activeSilentTokenRequests.delete(silentRequestKey); atsMeasurement.addStaticFields({ accessTokenSize: result.accessToken.length, idTokenSize: result.idToken.length }); atsMeasurement.endMeasurement({ success: true, fromCache: result.fromCache, isNativeBroker: result.fromNativeBroker, cacheLookupPolicy: request.cacheLookupPolicy, requestId: result.requestId, }); return result; }) .catch(function (error) { _this.activeSilentTokenRequests.delete(silentRequestKey); atsMeasurement.endMeasurement({ errorCode: error.errorCode, subErrorCode: error.subError, success: false }); throw error; }); this.activeSilentTokenRequests.set(silentRequestKey, response); return [2 /*return*/, response]; } else { this.logger.verbose("acquireTokenSilent has been called previously, returning the result from the first call", correlationId); // Discard measurements for memoized calls, as they are usually only a couple of ms and will artificially deflate metrics atsMeasurement.discardMeasurement(); return [2 /*return*/, cachedResponse]; } }); }); }; PublicClientApplication.prototype.trackPageVisibility = function () { if (!this.astsAsyncMeasurement) { return; } this.logger.info("Perf: Visibility change detected"); this.astsAsyncMeasurement.increment({ visibilityChangeCount: 1, }); }; /** * Silently acquire an access token for a given set of scopes. Will use cached token if available, otherwise will attempt to acquire a new token from the network via refresh token. * @param {@link (SilentRequest:type)} * @param {@link (AccountInfo:type)} * @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} */ PublicClientApplication.prototype.acquireTokenSilentAsync = function (request, account) { var _a; return __awaiter(this, void 0, void 0, function () { var result, silentRequest, silentCacheClient, silentRequest_1, requestWithCLP_1; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: this.performanceClient.addQueueMeasurement(PerformanceEvents.AcquireTokenSilentAsync, request.correlationId); this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_START, InteractionType.Silent, request); this.astsAsyncMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenSilentAsync, request.correlationId); (_a = this.astsAsyncMeasurement) === null || _a === void 0 ? void 0 : _a.increment({ visibilityChangeCount: 0 }); document.addEventListener("visibilitychange", this.trackPageVisibility); if (!(NativeMessageHandler.isNativeAvailable(this.config, this.logger, this.nativeExtensionProvider, request.authenticationScheme) && account.nativeAccountId)) return [3 /*break*/, 1]; this.logger.verbose("acquireTokenSilent - attempting to acquire token from native platform"); silentRequest = __assign(__assign({}, request), { account: account }); result = this.acquireTokenNative(silentRequest, ApiId.acquireTokenSilent_silentFlow).catch(function (e) { return __awaiter(_this, void 0, void 0, function () { var silentIframeClient; return __generator(this, function (_a) { // If native token acquisition fails for availability reasons fallback to web flow if (e instanceof NativeAuthError && e.isFatal()) { this.logger.verbose("acquireTokenSilent - native platform unavailable, falling back to web flow"); this.nativeExtensionProvider = undefined; // Prevent future requests from continuing to attempt silentIframeClient = this.createSilentIframeClient(request.correlationId); return [2 /*return*/, silentIframeClient.acquireToken(request)]; } throw e; }); }); }); return [3 /*break*/, 3]; case 1: this.logger.verbose("acquireTokenSilent - attempting to acquire token from web flow"); silentCacheClient = this.createSilentCacheClient(request.correlationId); this.performanceClient.setPreQueueTime(PerformanceEvents.InitializeSilentRequest, request.correlationId); return [4 /*yield*/, silentCacheClient.initializeSilentRequest(request, account)]; case 2: silentRequest_1 = _b.sent(); requestWithCLP_1 = __assign(__assign({}, request), { // set the request's CacheLookupPolicy to Default if it was not optionally passed in cacheLookupPolicy: request.cacheLookupPolicy || CacheLookupPolicy.Default }); this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenFromCache, silentRequest_1.correlationId); result = this.acquireTokenFromCache(silentCacheClient, silentRequest_1, requestWithCLP_1).catch(function (cacheError) { if (requestWithCLP_1.cacheLookupPolicy === CacheLookupPolicy.AccessToken) { throw cacheError; } // block the reload if it occurred inside a hidden iframe BrowserUtils.blockReloadInHiddenIframes(); _this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_NETWORK_START, InteractionType.Silent, silentRequest_1); _this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenByRefreshToken, silentRequest_1.correlationId); return _this.acquireTokenByRefreshToken(silentRequest_1, requestWithCLP_1).catch(function (refreshTokenError) { var isServerError = refreshTokenError instanceof ServerError; var isInteractionRequiredError = refreshTokenError instanceof InteractionRequiredAuthError; var isInvalidGrantError = (refreshTokenError.errorCode === BrowserConstants.INVALID_GRANT_ERROR); if ((!isServerError || !isInvalidGrantError || isInteractionRequiredError || requestWithCLP_1.cacheLookupPolicy === CacheLookupPolicy.AccessTokenAndRefreshToken || requestWithCLP_1.cacheLookupPolicy === CacheLookupPolicy.RefreshToken) && (requestWithCLP_1.cacheLookupPolicy !== CacheLookupPolicy.Skip)) { throw refreshTokenError; } _this.logger.verbose("Refresh token expired/invalid or CacheLookupPolicy is set to Skip, attempting acquire token by iframe.", request.correlationId); _this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenBySilentIframe, silentRequest_1.correlationId); return _this.acquireTokenBySilentIframe(silentRequest_1); }); }); _b.label = 3; case 3: return [2 /*return*/, result.then(function (response) { var _a; _this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_SUCCESS, InteractionType.Silent, response); (_a = _this.astsAsyncMeasurement) === null || _a === void 0 ? void 0 : _a.endMeasurement({ success: true, fromCache: response.fromCache, isNativeBroker: response.fromNativeBroker, requestId: response.requestId }); return response; }).catch(function (tokenRenewalError) { var _a; _this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_FAILURE, InteractionType.Silent, null, tokenRenewalError); (_a = _this.astsAsyncMeasurement) === null || _a === void 0 ? void 0 : _a.endMeasurement({ errorCode: tokenRenewalError.errorCode, subErrorCode: tokenRenewalError.subError, success: false }); throw tokenRenewalError; }).finally(function () { document.removeEventListener("visibilitychange", _this.trackPageVisibility); })]; } }); }); }; return PublicClientApplication; }(ClientApplication)); export { PublicClientApplication }; //# sourceMappingURL=PublicClientApplication.js.map