From 5e6321f7c16d330291a87e623769f800612f8465 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 11 Mar 2025 15:08:01 -0700 Subject: [PATCH 01/30] added isPlatformBrokerAvailable API --- .../broker/nativeBroker/PlatformDOMHandler.ts | 16 +++ .../src/controllers/IController.ts | 2 + .../src/controllers/StandardController.ts | 100 +++++++++++++++--- 3 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts new file mode 100644 index 0000000000..45e1d4055a --- /dev/null +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -0,0 +1,16 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { AuthenticationResult } from "../../response/AuthenticationResult.js"; + +export class PlatformDOMHandler { + async executeGetTokenRequest(request): AuthenticationResult { + const response = + await window.navigator.platformAuthentication.executeGetToken( + request + ); + return response; + } +} diff --git a/lib/msal-browser/src/controllers/IController.ts b/lib/msal-browser/src/controllers/IController.ts index 856f4abc38..b5b8dd85a2 100644 --- a/lib/msal-browser/src/controllers/IController.ts +++ b/lib/msal-browser/src/controllers/IController.ts @@ -121,4 +121,6 @@ export interface IController { /** @internal */ getPerformanceClient(): IPerformanceClient; + + isPlatformBrokerAvailable(): Promise; } diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index ee00bac23e..66b2aae728 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -87,6 +87,7 @@ import { createNewGuid } from "../crypto/BrowserCrypto.js"; import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; function getAccountType( account?: AccountInfo @@ -116,6 +117,25 @@ function preflightCheck( } } +/** + * declare a custom interface for the global window object to store the platform authentication configuration + */ +declare global { + interface Window { + platformConfiguration: Map< + string, + NativeMessageHandler | PlatformDOMHandler | null + >; + } +} + +/** + * Public method to indicate whether platform broker is available to make native token request. + */ +export function isPlatformBrokerAvailable(): boolean { + return window.platformConfiguration.size > 0; +} + export class StandardController implements IController { // OperatingContext protected readonly operatingContext: StandardOperatingContext; @@ -167,6 +187,11 @@ export class StandardController implements IController { // Flag representing whether or not the initialize API has been called and completed protected initialized: boolean; + protected platformConfiguration: Map< + string, + NativeMessageHandler | PlatformDOMHandler | null + >; + // Active requests private activeSilentTokenRequests: Map< string, @@ -287,6 +312,8 @@ export class StandardController implements IController { // Register listener functions this.trackPageVisibilityWithMeasurement = this.trackPageVisibilityWithMeasurement.bind(this); + + this.platformConfiguration = window.platformConfiguration || new Map(); } static async createController( @@ -346,17 +373,9 @@ export class StandardController implements IController { initCorrelationId )(initCorrelationId); - if (allowPlatformBroker) { - try { - this.nativeExtensionProvider = - await NativeMessageHandler.createProvider( - this.logger, - this.config.system.nativeBrokerHandshakeTimeout, - this.performanceClient - ); - } catch (e) { - this.logger.verbose(e as string); - } + if (allowPlatformBroker.allowPlatformBroker) { + // check if platform authentication is available via DOM or browser extension and create relevant handlers + await this.isPlatformBrokerAvailable(); } if (!this.config.cache.claimsBasedCachingEnabled) { @@ -385,6 +404,59 @@ export class StandardController implements IController { }); } + async isPlatformBrokerAvailable(): Promise { + const domPlatformApiSupported = await this.checkDomPlatformApiSupport(); + if (domPlatformApiSupported) { + this.cacheDomPlatformApiSupport(); + return true; + } + + if ( + this.nativeExtensionProvider || + this.platformConfiguration.get("msal.extension.platformAPISupport") + ) { + return true; + } + + return this.initializeNativeExtensionProvider(); + } + + private async checkDomPlatformApiSupport(): Promise { + if (!window.navigator?.platformAuthentication) { + return false; + } + + const supportedContracts = + await window.navigator.platformAuthentication.getSupportedContracts(); + return supportedContracts.includes("get-token-and-sign-out"); + } + + private cacheDomPlatformApiSupport(): void { + this.platformConfiguration.set( + "msal.dom.platformAPISupport", + new PlatformDOMHandler() + ); + } + + private async initializeNativeExtensionProvider(): Promise { + try { + this.nativeExtensionProvider = + await NativeMessageHandler.createProvider( + this.logger, + this.config.system.nativeBrokerHandshakeTimeout, + this.performanceClient + ); + this.platformConfiguration.set( + "msal.extension.platformAPISupport", + this.nativeExtensionProvider + ); + return true; + } catch (e) { + this.logger.verbose(e as string); + return false; + } + } + // #region Redirect Flow /** @@ -783,7 +855,11 @@ export class StandardController implements IController { let result: Promise; const pkce = this.getPreGeneratedPkceCodes(correlationId); - if (this.canUsePlatformBroker(request)) { + if ( + sessionStorage.getItem("msal.edge.platformAPIsSupported") === "true" + ) { + // initialize Edge native client class + } else if (this.canUsePlatformBroker(request)) { result = this.acquireTokenNative( { ...request, From ce0d102dd12e708c1afa20283d68e48c9be74d02 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 12 Mar 2025 13:39:59 -0700 Subject: [PATCH 02/30] updated isPlatformBrokerAvailable implementation --- .../src/controllers/IController.ts | 2 - .../src/controllers/StandardController.ts | 123 +++++++++--------- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/lib/msal-browser/src/controllers/IController.ts b/lib/msal-browser/src/controllers/IController.ts index b5b8dd85a2..856f4abc38 100644 --- a/lib/msal-browser/src/controllers/IController.ts +++ b/lib/msal-browser/src/controllers/IController.ts @@ -121,6 +121,4 @@ export interface IController { /** @internal */ getPerformanceClient(): IPerformanceClient; - - isPlatformBrokerAvailable(): Promise; } diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 66b2aae728..4f45840451 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -18,6 +18,7 @@ import { PerformanceCallbackFunction, IPerformanceClient, BaseAuthRequest, + LoggerOptions, PromptValue, InProgressPerformanceEvent, RequestThumbprint, @@ -35,7 +36,11 @@ import { DEFAULT_BROWSER_CACHE_MANAGER, } from "../cache/BrowserCacheManager.js"; import * as AccountManager from "../cache/AccountManager.js"; -import { BrowserConfiguration, CacheOptions } from "../config/Configuration.js"; +import { + BrowserConfiguration, + CacheOptions, + DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, +} from "../config/Configuration.js"; import { InteractionType, ApiId, @@ -88,6 +93,7 @@ import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { name, version } from "../packageMetadata.js"; function getAccountType( account?: AccountInfo @@ -132,8 +138,56 @@ declare global { /** * Public method to indicate whether platform broker is available to make native token request. */ -export function isPlatformBrokerAvailable(): boolean { - return window.platformConfiguration.size > 0; +export async function isPlatformBrokerAvailable( + logger?: Logger, + performanceClient?: IPerformanceClient +): Promise { + // check if any native platform API is available already + if ( + window.platformConfiguration.get("msal.dom.platformAPISupport") || + window.platformConfiguration.get("msal.extension.platformAPISupport") + ) { + return true; + } + + // Check if DOM platform API is supported + if (window.navigator?.platformAuthentication) { + const supportedContracts = + await window.navigator.platformAuthentication.getSupportedContracts(); + if (supportedContracts.includes("get-token-and-sign-out")) { + window.platformConfiguration.set( + "msal.dom.platformAPISupport", + new PlatformDOMHandler() + ); + return true; + } + } + + // Check and initialize native extension provider if available + try { + const defaultLoggerOptions: LoggerOptions = { + loggerCallback: (): void => { + // Empty logger callback + }, + piiLoggingEnabled: false, + }; + const defaultLogger = new Logger(defaultLoggerOptions, name, version); // Default logger + const defaultPerformanceClient = new IPerformanceClient(); + const nativeExtensionProvider = + await NativeMessageHandler.createProvider( + logger || defaultLogger, + DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, + performanceClient || defaultPerformanceClient + ); + window.platformConfiguration.set( + "msal.extension.platformAPISupport", + nativeExtensionProvider + ); + return true; + } catch (e) { + Logger.verbose(e as string); + return false; + } } export class StandardController implements IController { @@ -373,9 +427,15 @@ export class StandardController implements IController { initCorrelationId )(initCorrelationId); - if (allowPlatformBroker.allowPlatformBroker) { + if (allowPlatformBroker) { // check if platform authentication is available via DOM or browser extension and create relevant handlers - await this.isPlatformBrokerAvailable(); + await isPlatformBrokerAvailable( + this.logger, + this.performanceClient + ); + this.nativeExtensionProvider = window.platformConfiguration.get( + "msal.extension.platformAPISupport" + ) as NativeMessageHandler; } if (!this.config.cache.claimsBasedCachingEnabled) { @@ -404,59 +464,6 @@ export class StandardController implements IController { }); } - async isPlatformBrokerAvailable(): Promise { - const domPlatformApiSupported = await this.checkDomPlatformApiSupport(); - if (domPlatformApiSupported) { - this.cacheDomPlatformApiSupport(); - return true; - } - - if ( - this.nativeExtensionProvider || - this.platformConfiguration.get("msal.extension.platformAPISupport") - ) { - return true; - } - - return this.initializeNativeExtensionProvider(); - } - - private async checkDomPlatformApiSupport(): Promise { - if (!window.navigator?.platformAuthentication) { - return false; - } - - const supportedContracts = - await window.navigator.platformAuthentication.getSupportedContracts(); - return supportedContracts.includes("get-token-and-sign-out"); - } - - private cacheDomPlatformApiSupport(): void { - this.platformConfiguration.set( - "msal.dom.platformAPISupport", - new PlatformDOMHandler() - ); - } - - private async initializeNativeExtensionProvider(): Promise { - try { - this.nativeExtensionProvider = - await NativeMessageHandler.createProvider( - this.logger, - this.config.system.nativeBrokerHandshakeTimeout, - this.performanceClient - ); - this.platformConfiguration.set( - "msal.extension.platformAPISupport", - this.nativeExtensionProvider - ); - return true; - } catch (e) { - this.logger.verbose(e as string); - return false; - } - } - // #region Redirect Flow /** From a1b0fa11ce86f94dbd6390e3f4ecacaab6315571 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 12 Mar 2025 14:02:46 -0700 Subject: [PATCH 03/30] code cleanup --- .../broker/nativeBroker/PlatformDOMHandler.ts | 16 ---------------- .../src/controllers/StandardController.ts | 13 +------------ 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts deleted file mode 100644 index 45e1d4055a..0000000000 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { AuthenticationResult } from "../../response/AuthenticationResult.js"; - -export class PlatformDOMHandler { - async executeGetTokenRequest(request): AuthenticationResult { - const response = - await window.navigator.platformAuthentication.executeGetToken( - request - ); - return response; - } -} diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 4f45840451..53950024c0 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -241,11 +241,6 @@ export class StandardController implements IController { // Flag representing whether or not the initialize API has been called and completed protected initialized: boolean; - protected platformConfiguration: Map< - string, - NativeMessageHandler | PlatformDOMHandler | null - >; - // Active requests private activeSilentTokenRequests: Map< string, @@ -366,8 +361,6 @@ export class StandardController implements IController { // Register listener functions this.trackPageVisibilityWithMeasurement = this.trackPageVisibilityWithMeasurement.bind(this); - - this.platformConfiguration = window.platformConfiguration || new Map(); } static async createController( @@ -862,11 +855,7 @@ export class StandardController implements IController { let result: Promise; const pkce = this.getPreGeneratedPkceCodes(correlationId); - if ( - sessionStorage.getItem("msal.edge.platformAPIsSupported") === "true" - ) { - // initialize Edge native client class - } else if (this.canUsePlatformBroker(request)) { + if (this.canUsePlatformBroker(request)) { result = this.acquireTokenNative( { ...request, From 381473c23dc2dfd0437ac36a69fddecc24dcb6e8 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 17 Mar 2025 19:42:34 -0700 Subject: [PATCH 04/30] updated isPlatformBrokerAvailable() --- .../src/controllers/StandardController.ts | 153 ++++++++++-------- lib/msal-browser/src/index.ts | 2 + 2 files changed, 84 insertions(+), 71 deletions(-) diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 13c218f9aa..bc707fe93d 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -30,6 +30,7 @@ import { buildStaticAuthorityOptions, InteractionRequiredAuthErrorCodes, PkceCodes, + LogLevel, } from "@azure/msal-common/browser"; import { BrowserCacheManager, @@ -92,8 +93,8 @@ import { createNewGuid } from "../crypto/BrowserCrypto.js"; import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; import { name, version } from "../packageMetadata.js"; +import { BrowserPerformanceClient } from "../telemetry/BrowserPerformanceClient.js"; function getAccountType( account?: AccountInfo @@ -123,41 +124,50 @@ function preflightCheck( } } -/** - * declare a custom interface for the global window object to store the platform authentication configuration - */ -declare global { - interface Window { - platformConfiguration: Map< - string, - NativeMessageHandler | PlatformDOMHandler | null - >; - } -} - /** * Public method to indicate whether platform broker is available to make native token request. */ export async function isPlatformBrokerAvailable( - logger?: Logger, + logger?: LoggerOptions, performanceClient?: IPerformanceClient ): Promise { - // check if any native platform API is available already - if ( - window.platformConfiguration.get("msal.dom.platformAPISupport") || - window.platformConfiguration.get("msal.extension.platformAPISupport") - ) { - return true; - } + const defaultLoggerOptions: LoggerOptions = { + loggerCallback: (): void => { + // Empty logger callback + }, + piiLoggingEnabled: false, + logLevel: LogLevel.Trace, + }; + + const temporaryLogger = new Logger( + logger || defaultLoggerOptions, + name, + version + ); // Default logger + + const defaultPerformanceClientConfig = { + auth: { + clientId: "test-clientid", + }, + }; + const temporaryTelemetryClient: IPerformanceClient = + performanceClient || + new BrowserPerformanceClient(defaultPerformanceClientConfig); + + temporaryLogger.trace("isPlatformBrokerAvailable called"); // Check if DOM platform API is supported + + // @ts-ignore if (window.navigator?.platformAuthentication) { const supportedContracts = - await window.navigator.platformAuthentication.getSupportedContracts(); + // @ts-ignore + await window.navigator.platformAuthentication.getSupportedContracts( + "MicrosoftEntra" + ); if (supportedContracts.includes("get-token-and-sign-out")) { - window.platformConfiguration.set( - "msal.dom.platformAPISupport", - new PlatformDOMHandler() + temporaryLogger.trace( + "Platform API available in DOM, returning true" ); return true; } @@ -165,27 +175,25 @@ export async function isPlatformBrokerAvailable( // Check and initialize native extension provider if available try { - const defaultLoggerOptions: LoggerOptions = { - loggerCallback: (): void => { - // Empty logger callback - }, - piiLoggingEnabled: false, - }; - const defaultLogger = new Logger(defaultLoggerOptions, name, version); // Default logger - const defaultPerformanceClient = new IPerformanceClient(); const nativeExtensionProvider = await NativeMessageHandler.createProvider( - logger || defaultLogger, + temporaryLogger, DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, - performanceClient || defaultPerformanceClient + temporaryTelemetryClient ); - window.platformConfiguration.set( - "msal.extension.platformAPISupport", - nativeExtensionProvider - ); - return true; + if (nativeExtensionProvider) { + temporaryLogger.trace( + "Platform API available via extension, returning true" + ); + return true; + } else { + temporaryLogger.trace( + "Platform API not available, returning false" + ); + return false; + } } catch (e) { - Logger.verbose(e as string); + temporaryLogger.trace(e as string); return false; } } @@ -230,7 +238,7 @@ export class StandardController implements IController { >; // Native Extension Provider - protected nativeExtensionProvider: NativeMessageHandler | undefined; + protected platformAuthProvider: NativeMessageHandler | undefined; // Hybrid auth code responses private hybridAuthCodeResponses: Map>; @@ -421,14 +429,17 @@ export class StandardController implements IController { )(initCorrelationId); if (allowPlatformBroker) { - // check if platform authentication is available via DOM or browser extension and create relevant handlers - await isPlatformBrokerAvailable( - this.logger, - this.performanceClient - ); - this.nativeExtensionProvider = window.platformConfiguration.get( - "msal.extension.platformAPISupport" - ) as NativeMessageHandler; + try { + // check if platform authentication is available via DOM or browser extension and create relevant handlers + this.platformAuthProvider = + await NativeMessageHandler.createProvider( + this.logger, + this.config.system.nativeBrokerHandshakeTimeout, + this.performanceClient + ); + } catch (e) { + this.logger.verbose(e as string); + } } if (!this.config.cache.claimsBasedCachingEnabled) { @@ -517,9 +528,9 @@ export class StandardController implements IController { NativeMessageHandler.isPlatformBrokerAvailable( this.config, this.logger, - this.nativeExtensionProvider + this.platformAuthProvider ) && - this.nativeExtensionProvider && + this.platformAuthProvider && !hash; const correlationId = useNative ? request?.correlationId @@ -537,7 +548,7 @@ export class StandardController implements IController { ); let redirectResponse: Promise; - if (useNative && this.nativeExtensionProvider) { + if (useNative && this.platformAuthProvider) { this.logger.trace( "handleRedirectPromise - acquiring token from native platform" ); @@ -550,7 +561,7 @@ export class StandardController implements IController { this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, request.accountId, this.nativeInternalStorage, request.correlationId @@ -738,7 +749,7 @@ export class StandardController implements IController { let result: Promise; if ( - this.nativeExtensionProvider && + this.platformAuthProvider && this.canUsePlatformBroker(request) ) { const nativeClient = new NativeInteractionClient( @@ -750,7 +761,7 @@ export class StandardController implements IController { this.navigationClient, ApiId.acquireTokenRedirect, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, this.getNativeAccountId(request), this.nativeInternalStorage, correlationId @@ -762,7 +773,7 @@ export class StandardController implements IController { e instanceof NativeAuthError && isFatalNativeAuthError(e) ) { - this.nativeExtensionProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt const redirectClient = this.createRedirectClient(correlationId); return redirectClient.acquireToken(request); @@ -877,7 +888,7 @@ export class StandardController implements IController { e instanceof NativeAuthError && isFatalNativeAuthError(e) ) { - this.nativeExtensionProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt const popupClient = this.createPopupClient(correlationId); return popupClient.acquireToken(request, pkce); @@ -1036,7 +1047,7 @@ export class StandardController implements IController { ).catch((e: AuthError) => { // If native token acquisition fails for availability reasons fallback to standard flow if (e instanceof NativeAuthError && isFatalNativeAuthError(e)) { - this.nativeExtensionProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt const silentIframeClient = this.createSilentIframeClient( validRequest.correlationId ); @@ -1193,7 +1204,7 @@ export class StandardController implements IController { e instanceof NativeAuthError && isFatalNativeAuthError(e) ) { - this.nativeExtensionProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt } throw e; }); @@ -1595,7 +1606,7 @@ export class StandardController implements IController { cacheLookupPolicy?: CacheLookupPolicy ): Promise { this.logger.trace("acquireTokenNative called"); - if (!this.nativeExtensionProvider) { + if (!this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); @@ -1610,7 +1621,7 @@ export class StandardController implements IController { this.navigationClient, apiId, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, accountId || this.getNativeAccountId(request), this.nativeInternalStorage, request.correlationId @@ -1632,7 +1643,7 @@ export class StandardController implements IController { !NativeMessageHandler.isPlatformBrokerAvailable( this.config, this.logger, - this.nativeExtensionProvider, + this.platformAuthProvider, request.authenticationScheme ) ) { @@ -1702,7 +1713,7 @@ export class StandardController implements IController { this.navigationClient, this.performanceClient, this.nativeInternalStorage, - this.nativeExtensionProvider, + this.platformAuthProvider, correlationId ); } @@ -1721,7 +1732,7 @@ export class StandardController implements IController { this.navigationClient, this.performanceClient, this.nativeInternalStorage, - this.nativeExtensionProvider, + this.platformAuthProvider, correlationId ); } @@ -1743,7 +1754,7 @@ export class StandardController implements IController { ApiId.ssoSilent, this.performanceClient, this.nativeInternalStorage, - this.nativeExtensionProvider, + this.platformAuthProvider, correlationId ); } @@ -1762,7 +1773,7 @@ export class StandardController implements IController { this.eventHandler, this.navigationClient, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, correlationId ); } @@ -1781,7 +1792,7 @@ export class StandardController implements IController { this.eventHandler, this.navigationClient, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, correlationId ); } @@ -1801,7 +1812,7 @@ export class StandardController implements IController { this.navigationClient, ApiId.acquireTokenByCode, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, correlationId ); } @@ -2316,7 +2327,7 @@ export class StandardController implements IController { NativeMessageHandler.isPlatformBrokerAvailable( this.config, this.logger, - this.nativeExtensionProvider, + this.platformAuthProvider, silentRequest.authenticationScheme ) && silentRequest.account.nativeAccountId @@ -2335,7 +2346,7 @@ export class StandardController implements IController { this.logger.verbose( "acquireTokenSilent - native platform unavailable, falling back to web flow" ); - this.nativeExtensionProvider = undefined; // Prevent future requests from continuing to attempt + this.platformAuthProvider = undefined; // Prevent future requests from continuing to attempt // Cache will not contain tokens, given that previous WAM requests succeeded. Skip cache and RT renewal and go straight to iframe renewal throw createClientAuthError( diff --git a/lib/msal-browser/src/index.ts b/lib/msal-browser/src/index.ts index db8b912914..34b0fc2be5 100644 --- a/lib/msal-browser/src/index.ts +++ b/lib/msal-browser/src/index.ts @@ -160,3 +160,5 @@ export { } from "@azure/msal-common/browser"; export { version } from "./packageMetadata.js"; + +export { isPlatformBrokerAvailable } from "./controllers/StandardController.js"; From 15dcb07743095a27edb5c7f8cc1a4241c653ccb1 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 31 Mar 2025 08:36:34 -0700 Subject: [PATCH 05/30] added initializeNativeDOMRequest --- .../nativeBroker/NativeMessageHandler.ts | 49 --- .../src/broker/nativeBroker/NativeRequest.ts | 24 +- .../src/broker/nativeBroker/NativeResponse.ts | 32 ++ .../nativeBroker/PlatformAuthProvider.ts | 148 +++++++ .../broker/nativeBroker/PlatformDOMHandler.ts | 81 ++++ .../src/cache/BrowserCacheManager.ts | 6 +- .../src/controllers/StandardController.ts | 217 +++++----- lib/msal-browser/src/index.ts | 2 +- .../BaseInteractionClient.ts | 13 +- .../NativeInteractionClient.ts | 403 ++++++++++++------ .../src/interaction_client/PopupClient.ts | 26 +- .../src/interaction_client/RedirectClient.ts | 26 +- .../SilentAuthCodeClient.ts | 7 +- .../interaction_client/SilentIframeClient.ts | 17 +- .../src/utils/BrowserConstants.ts | 1 + .../test/app/PublicClientApplication.spec.ts | 6 +- 16 files changed, 722 insertions(+), 336 deletions(-) create mode 100644 lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts create mode 100644 lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts index 3314601734..75a672b4ef 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts @@ -364,53 +364,4 @@ export class NativeMessageHandler { getExtensionVersion(): string | undefined { return this.extensionVersion; } - - /** - * Returns boolean indicating whether or not the request should attempt to use native broker - * @param logger - * @param config - * @param nativeExtensionProvider - * @param authenticationScheme - */ - static isPlatformBrokerAvailable( - config: BrowserConfiguration, - logger: Logger, - nativeExtensionProvider?: NativeMessageHandler, - authenticationScheme?: AuthenticationScheme - ): boolean { - logger.trace("isPlatformBrokerAvailable called"); - if (!config.system.allowPlatformBroker) { - logger.trace( - "isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false" - ); - // Developer disabled WAM - return false; - } - - if (!nativeExtensionProvider) { - logger.trace( - "isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false" - ); - // Extension is not available - return false; - } - - if (authenticationScheme) { - switch (authenticationScheme) { - case AuthenticationScheme.BEARER: - case AuthenticationScheme.POP: - logger.trace( - "isPlatformBrokerAvailable: authenticationScheme is supported, returning true" - ); - return true; - default: - logger.trace( - "isPlatformBrokerAvailable: authenticationScheme is not supported, returning false" - ); - return false; - } - } - - return true; - } } diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts index 8402d57805..0ccce97b96 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts @@ -9,7 +9,7 @@ import { StoreInCache, StringDict } from "@azure/msal-common/browser"; /** * Token request which native broker will use to acquire tokens */ -export type NativeTokenRequest = { +export type NativeExtensionTokenRequest = { accountId: string; // WAM specific account id used for identification of WAM account. This can be any broker-id eventually clientId: string; authority: string; @@ -40,7 +40,7 @@ export type NativeTokenRequest = { */ export type NativeExtensionRequestBody = { method: NativeExtensionMethod; - request?: NativeTokenRequest; + request?: NativeExtensionTokenRequest; }; /** @@ -52,3 +52,23 @@ export type NativeExtensionRequest = { extensionId?: string; body: NativeExtensionRequestBody; }; + +export type PlatformDOMTokenRequest = { + brokerId: string; + accountId?: string; + clientId: string; + authority: string; + scope: string; + redirectUri: string; + correlationId: string; + isSecurityTokenService: string; + state?: string; + /* + * Known optional parameters will go into extraQueryParameters. + * List of known parameters is: + * "prompt", "nonce", "claims", "loginHint", "instanceAware", "windowTitleSubstring", "extendedExpiryToken", "storeInCache", + * PoP related paramters: "reqCnf", "keyId", "tokenType", "shrClaims", "shrNonce", "resourceRequestMethod", "resourceRequestUri", "signPopToken" + */ + extraParameters?: StringDict; + embeddedClientId?: string; +}; diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts index 79392395df..56fd3c6885 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. */ +import { AccountInfo } from "@azure/msal-common"; + /** * Account properties returned by Native Platform e.g. WAM */ @@ -54,3 +56,33 @@ export type MATS = { http_status?: number; http_event_count?: number; }; + +export type PlatformDOMResponse = { + isSuccess: boolean; + state?: string; + accessToken?: string; + expiresIn: number; + account: Account; + clientInfo?: string; + idToken?: string; + scopes?: string; + proofOfPossessionPayload?: string; + extendedLifetimeToken: boolean; + error: ErrorResult; + properties?: Record; +}; + +export type ErrorResult = { + code: string; + description?: string; + errorCode: string; + protocolError?: string; + status: string; + properties?: Record; +}; + +export type Account = { + id: string; + userName: string; + properties?: Record; +}; diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts new file mode 100644 index 0000000000..4e929c7060 --- /dev/null +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -0,0 +1,148 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { + LoggerOptions, + IPerformanceClient, + LogLevel, + Logger, + AuthenticationScheme, +} from "@azure/msal-common"; +import { name, version } from "../../packageMetadata.js"; +import { + BrowserConfiguration, + DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, +} from "../../config/Configuration.js"; +import { BrowserPerformanceClient } from "../../telemetry/BrowserPerformanceClient.js"; +import { NativeMessageHandler } from "./NativeMessageHandler.js"; +import { NativeConstants } from "../../utils/BrowserConstants.js"; +import { PlatformDOMHandler } from "./PlatformDOMHandler.js"; + +export const PLATFORM_EXTENSION_PROVIDER = "NativeMessageHandler"; +export const PLATFORM_DOM_PROVIDER = "PlatformDOMHandler"; + +export async function isPlatformBrokerAvailable( + loggerOptions?: LoggerOptions, + perfClient?: IPerformanceClient +): Promise { + const defaultLoggerOptions: LoggerOptions = { + loggerCallback: (): void => { + // Empty logger callback + }, + piiLoggingEnabled: false, + logLevel: LogLevel.Trace, + }; + + const logger = new Logger( + loggerOptions || defaultLoggerOptions, + name, + version + ); + + logger.trace("isPlatformBrokerAvailable called"); + + const defaultPerformanceClientConfig = { + auth: { + clientId: "", + }, + }; + + const performanceClient = + perfClient || + new BrowserPerformanceClient(defaultPerformanceClientConfig); + + if (!window) { + logger.trace("Non DOM environment detected, returning false"); + return false; + } + + // Check if DOM platform API is supported + + // @ts-ignore + if (window.navigator?.platformAuthentication) { + const supportedContracts = + // @ts-ignore + await window.navigator.platformAuthentication.getSupportedContracts( + NativeConstants.MICROSOFT_ENTRA_BROKERID + ); + if (supportedContracts.includes("get-token-and-sign-out")) { + logger.trace("Platform auth available in DOM"); + return true; + } + } + + // Check and initialize native extension provider if available + try { + const nativeExtensionProvider = + await NativeMessageHandler.createProvider( + logger, + DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, + performanceClient + ); + if (nativeExtensionProvider) { + logger.trace( + "Platform auth available via extension, returning true" + ); + return true; + } else { + logger.trace("Platform auth not available, returning false"); + return false; + } + } catch (e) { + logger.trace(e as string); + return false; + } +} + +export class PlatformAuthProvider { + /** + * Returns boolean indicating whether or not the request should attempt to use native broker + * @param logger + * @param config + * @param nativeExtensionProvider + * @param authenticationScheme + */ + static isBrokerAvailable( + config: BrowserConfiguration, + logger: Logger, + platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, + authenticationScheme?: AuthenticationScheme + ): boolean { + logger.trace("isPlatformBrokerAvailable called"); + if (!config.system.allowPlatformBroker) { + logger.trace( + "isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false" + ); + // Developer disabled WAM + return false; + } + + if (!platformAuthProvider) { + logger.trace( + "isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false" + ); + // Extension is not available + return false; + } + + if (authenticationScheme) { + switch (authenticationScheme) { + case AuthenticationScheme.BEARER: + case AuthenticationScheme.POP: + logger.trace( + "isPlatformBrokerAvailable: authenticationScheme is supported, returning true" + ); + return true; + default: + logger.trace( + "isPlatformBrokerAvailable: authenticationScheme is not supported, returning false" + ); + return false; + } + } + + return true; + } +} diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts new file mode 100644 index 0000000000..15dc9d4d5d --- /dev/null +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { Logger } from "@azure/msal-common"; +import { AuthenticationResult } from "../../response/AuthenticationResult.js"; +import { PlatformDOMTokenRequest } from "./NativeRequest.js"; +import { IPerformanceClient } from "../../../../msal-common/lib/types/exports-browser-only.js"; +import { createNewGuid } from "../../crypto/BrowserCrypto.js"; +import { NativeConstants } from "../../utils/BrowserConstants.js"; +import { ClearCacheRequest } from "../../request/ClearCacheRequest.js"; +import { EndSessionRequest } from "../../request/EndSessionRequest.js"; + +export class PlatformDOMHandler { + protected logger: Logger; + protected performanceClient: IPerformanceClient; + protected correlationId: string; + protected extensionId: string; + protected extensionVersion: string; + + constructor( + logger: Logger, + performanceClient: IPerformanceClient, + extensionId?: string, + correlationId?: string + ) { + this.logger = logger; + this.performanceClient = performanceClient; + this.extensionId = + extensionId || NativeConstants.MICROSOFT_ENTRA_BROKERID; + this.correlationId = correlationId || createNewGuid(); + this.extensionVersion = "1.0.0"; + } + + /** + * Returns the Id for the browser extension this handler is communicating with + * @returns + */ + getExtensionId(): string { + return this.extensionId; + } + + getExtensionVersion(): string | undefined { + return this.extensionVersion; + } + + async sendMessage( + request: PlatformDOMTokenRequest + ): Promise { + this.logger.trace("PlatformDOMHandler: acquireToken called"); + + try { + const response = + // @ts-ignore + await window.navigator.platformAuthentication.executeGetToken( + request + ); + this.logger.trace( + "PlatformDOMHandler: acquireToken response received" + ); + // NEED TO REMOVE THIS LATER + this.logger.trace( + "PlatformDOMHandler: acquireToken response", + response + ); + return response as AuthenticationResult; + } catch (e) { + this.logger.error("PlatformDOMHandler: acquireToken error"); + throw e; + } + } + + logout( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + request: EndSessionRequest | ClearCacheRequest | undefined + ): Promise { + this.logger.trace("PlatformDOMHandler: logout called"); + throw new Error("Method not implemented."); + } +} diff --git a/lib/msal-browser/src/cache/BrowserCacheManager.ts b/lib/msal-browser/src/cache/BrowserCacheManager.ts index 76b506607e..dceb63f24c 100644 --- a/lib/msal-browser/src/cache/BrowserCacheManager.ts +++ b/lib/msal-browser/src/cache/BrowserCacheManager.ts @@ -57,7 +57,7 @@ import { SessionStorage } from "./SessionStorage.js"; import { MemoryStorage } from "./MemoryStorage.js"; import { IWindowStorage } from "./IWindowStorage.js"; import { extractBrowserRequestState } from "../utils/BrowserProtocolUtils.js"; -import { NativeTokenRequest } from "../broker/nativeBroker/NativeRequest.js"; +import { NativeExtensionTokenRequest } from "../broker/nativeBroker/NativeRequest.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { SilentRequest } from "../request/SilentRequest.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; @@ -1335,7 +1335,7 @@ export class BrowserCacheManager extends CacheManager { /** * Gets cached native request for redirect flows */ - getCachedNativeRequest(): NativeTokenRequest | null { + getCachedNativeRequest(): NativeExtensionTokenRequest | null { this.logger.trace("BrowserCacheManager.getCachedNativeRequest called"); const cachedRequest = this.getTemporaryCache( TemporaryCacheKeys.NATIVE_REQUEST, @@ -1350,7 +1350,7 @@ export class BrowserCacheManager extends CacheManager { const parsedRequest = this.validateAndParseJson( cachedRequest - ) as NativeTokenRequest; + ) as NativeExtensionTokenRequest; if (!parsedRequest) { this.logger.error( "BrowserCacheManager.getCachedNativeRequest: Unable to parse native request" diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index bc707fe93d..6e6337ced9 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -18,7 +18,6 @@ import { PerformanceCallbackFunction, IPerformanceClient, BaseAuthRequest, - LoggerOptions, PromptValue, InProgressPerformanceEvent, getRequestThumbprint, @@ -30,18 +29,13 @@ import { buildStaticAuthorityOptions, InteractionRequiredAuthErrorCodes, PkceCodes, - LogLevel, } from "@azure/msal-common/browser"; import { BrowserCacheManager, DEFAULT_BROWSER_CACHE_MANAGER, } from "../cache/BrowserCacheManager.js"; import * as AccountManager from "../cache/AccountManager.js"; -import { - BrowserConfiguration, - CacheOptions, - DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, -} from "../config/Configuration.js"; +import { BrowserConfiguration, CacheOptions } from "../config/Configuration.js"; import { InteractionType, ApiId, @@ -52,6 +46,7 @@ import { DEFAULT_REQUEST, BrowserConstants, iFrameRenewalPolicies, + NativeConstants, } from "../utils/BrowserConstants.js"; import * as BrowserUtils from "../utils/BrowserUtils.js"; import { RedirectRequest } from "../request/RedirectRequest.js"; @@ -83,7 +78,7 @@ import { BrowserAuthErrorCodes, } from "../error/BrowserAuthError.js"; import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js"; -import { NativeTokenRequest } from "../broker/nativeBroker/NativeRequest.js"; +import { NativeExtensionTokenRequest } from "../broker/nativeBroker/NativeRequest.js"; import { StandardOperatingContext } from "../operatingcontext/StandardOperatingContext.js"; import { BaseOperatingContext } from "../operatingcontext/BaseOperatingContext.js"; import { IController } from "./IController.js"; @@ -93,8 +88,12 @@ import { createNewGuid } from "../crypto/BrowserCrypto.js"; import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { name, version } from "../packageMetadata.js"; -import { BrowserPerformanceClient } from "../telemetry/BrowserPerformanceClient.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { + PLATFORM_DOM_PROVIDER, + PLATFORM_EXTENSION_PROVIDER, + PlatformAuthProvider, +} from "../broker/nativeBroker/PlatformAuthProvider.js"; function getAccountType( account?: AccountInfo @@ -124,80 +123,6 @@ function preflightCheck( } } -/** - * Public method to indicate whether platform broker is available to make native token request. - */ -export async function isPlatformBrokerAvailable( - logger?: LoggerOptions, - performanceClient?: IPerformanceClient -): Promise { - const defaultLoggerOptions: LoggerOptions = { - loggerCallback: (): void => { - // Empty logger callback - }, - piiLoggingEnabled: false, - logLevel: LogLevel.Trace, - }; - - const temporaryLogger = new Logger( - logger || defaultLoggerOptions, - name, - version - ); // Default logger - - const defaultPerformanceClientConfig = { - auth: { - clientId: "test-clientid", - }, - }; - const temporaryTelemetryClient: IPerformanceClient = - performanceClient || - new BrowserPerformanceClient(defaultPerformanceClientConfig); - - temporaryLogger.trace("isPlatformBrokerAvailable called"); - - // Check if DOM platform API is supported - - // @ts-ignore - if (window.navigator?.platformAuthentication) { - const supportedContracts = - // @ts-ignore - await window.navigator.platformAuthentication.getSupportedContracts( - "MicrosoftEntra" - ); - if (supportedContracts.includes("get-token-and-sign-out")) { - temporaryLogger.trace( - "Platform API available in DOM, returning true" - ); - return true; - } - } - - // Check and initialize native extension provider if available - try { - const nativeExtensionProvider = - await NativeMessageHandler.createProvider( - temporaryLogger, - DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, - temporaryTelemetryClient - ); - if (nativeExtensionProvider) { - temporaryLogger.trace( - "Platform API available via extension, returning true" - ); - return true; - } else { - temporaryLogger.trace( - "Platform API not available, returning false" - ); - return false; - } - } catch (e) { - temporaryLogger.trace(e as string); - return false; - } -} - export class StandardController implements IController { // OperatingContext protected readonly operatingContext: StandardOperatingContext; @@ -238,7 +163,12 @@ export class StandardController implements IController { >; // Native Extension Provider - protected platformAuthProvider: NativeMessageHandler | undefined; + protected platformAuthProvider: + | NativeMessageHandler + | PlatformDOMHandler + | undefined; + + private platformAuthType: string; // Hybrid auth code responses private hybridAuthCodeResponses: Map>; @@ -369,6 +299,8 @@ export class StandardController implements IController { // Register listener functions this.trackPageVisibilityWithMeasurement = this.trackPageVisibilityWithMeasurement.bind(this); + + this.platformAuthType = Constants.EMPTY_STRING; } static async createController( @@ -431,12 +363,7 @@ export class StandardController implements IController { if (allowPlatformBroker) { try { // check if platform authentication is available via DOM or browser extension and create relevant handlers - this.platformAuthProvider = - await NativeMessageHandler.createProvider( - this.logger, - this.config.system.nativeBrokerHandshakeTimeout, - this.performanceClient - ); + await this.getPlatformAuthProvider(); } catch (e) { this.logger.verbose(e as string); } @@ -468,6 +395,72 @@ export class StandardController implements IController { }); } + protected async getPlatformAuthProvider( + correlationId?: string + ): Promise { + this.logger.trace("getPlatformAuthProvider called", correlationId); + + const domPlatformApiSupported = await this.checkDOMPlatformSupport( + correlationId + ); + + if (domPlatformApiSupported) { + this.platformAuthProvider = domPlatformApiSupported; + this.platformAuthType = PLATFORM_DOM_PROVIDER; + } else { + this.platformAuthProvider = + await NativeMessageHandler.createProvider( + this.logger, + this.config.system.nativeBrokerHandshakeTimeout, + this.performanceClient + ); + this.platformAuthType = PLATFORM_EXTENSION_PROVIDER; + + this.logger.trace( + "Platform API available via browser extension", + correlationId + ); + } + } + + protected async checkDOMPlatformSupport( + correlationId?: string + ): Promise { + this.logger.trace("checkDOMPlatformSupport called", correlationId); + + if (!this.isBrowserEnvironment) { + this.logger.info("in non-browser environment, returning false."); + return; + } + + // @ts-ignore + if (window.navigator?.platformAuthentication) { + const supportedContracts = + // @ts-ignore + await window.navigator.platformAuthentication.getSupportedContracts( + NativeConstants.MICROSOFT_ENTRA_BROKERID + ); + if (supportedContracts.includes("get-token-and-sign-out")) { + this.logger.trace( + "Platform API available in DOM", + correlationId + ); + return new PlatformDOMHandler( + this.logger, + this.performanceClient, + NativeConstants.MICROSOFT_ENTRA_BROKERID, + correlationId + ); + } + } + + this.logger.trace( + "Platform DOM API not available, returning", + correlationId + ); + return; + } + // #region Redirect Flow /** @@ -521,17 +514,9 @@ export class StandardController implements IController { hash?: string ): Promise { const loggedInAccounts = this.getAllAccounts(); - const request: NativeTokenRequest | null = + const request: NativeExtensionTokenRequest | null = this.browserStorage.getCachedNativeRequest(); - const useNative = - request && - NativeMessageHandler.isPlatformBrokerAvailable( - this.config, - this.logger, - this.platformAuthProvider - ) && - this.platformAuthProvider && - !hash; + const useNative = request && this.platformAuthProvider && !hash; const correlationId = useNative ? request?.correlationId : this.browserStorage.getTemporaryCache( @@ -562,6 +547,7 @@ export class StandardController implements IController { ApiId.handleRedirectPromise, this.performanceClient, this.platformAuthProvider, + this.platformAuthType, request.accountId, this.nativeInternalStorage, request.correlationId @@ -762,6 +748,7 @@ export class StandardController implements IController { ApiId.acquireTokenRedirect, this.performanceClient, this.platformAuthProvider, + this.platformAuthType, this.getNativeAccountId(request), this.nativeInternalStorage, correlationId @@ -774,6 +761,7 @@ export class StandardController implements IController { isFatalNativeAuthError(e) ) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthType = Constants.EMPTY_STRING; const redirectClient = this.createRedirectClient(correlationId); return redirectClient.acquireToken(request); @@ -889,6 +877,7 @@ export class StandardController implements IController { isFatalNativeAuthError(e) ) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthType = Constants.EMPTY_STRING; const popupClient = this.createPopupClient(correlationId); return popupClient.acquireToken(request, pkce); @@ -1048,6 +1037,7 @@ export class StandardController implements IController { // If native token acquisition fails for availability reasons fallback to standard flow if (e instanceof NativeAuthError && isFatalNativeAuthError(e)) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthType = Constants.EMPTY_STRING; const silentIframeClient = this.createSilentIframeClient( validRequest.correlationId ); @@ -1205,6 +1195,7 @@ export class StandardController implements IController { isFatalNativeAuthError(e) ) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt + this.platformAuthType = Constants.EMPTY_STRING; } throw e; }); @@ -1606,6 +1597,11 @@ export class StandardController implements IController { cacheLookupPolicy?: CacheLookupPolicy ): Promise { this.logger.trace("acquireTokenNative called"); + if (!this.platformAuthType) { + throw createBrowserAuthError( + BrowserAuthErrorCodes.nativeConnectionNotEstablished + ); + } if (!this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished @@ -1622,6 +1618,7 @@ export class StandardController implements IController { apiId, this.performanceClient, this.platformAuthProvider, + this.platformAuthType, accountId || this.getNativeAccountId(request), this.nativeInternalStorage, request.correlationId @@ -1639,8 +1636,15 @@ export class StandardController implements IController { accountId?: string ): boolean { this.logger.trace("canUsePlatformBroker called"); + if (!this.platformAuthType) { + this.logger.trace( + "canUsePlatformBroker: platform broker unavilable, returning false" + ); + return false; + } + if ( - !NativeMessageHandler.isPlatformBrokerAvailable( + !PlatformAuthProvider.isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, @@ -1714,6 +1718,7 @@ export class StandardController implements IController { this.performanceClient, this.nativeInternalStorage, this.platformAuthProvider, + this.platformAuthType, correlationId ); } @@ -1733,6 +1738,7 @@ export class StandardController implements IController { this.performanceClient, this.nativeInternalStorage, this.platformAuthProvider, + this.platformAuthType, correlationId ); } @@ -1755,6 +1761,7 @@ export class StandardController implements IController { this.performanceClient, this.nativeInternalStorage, this.platformAuthProvider, + this.platformAuthType, correlationId ); } @@ -1774,6 +1781,7 @@ export class StandardController implements IController { this.navigationClient, this.performanceClient, this.platformAuthProvider, + this.platformAuthType, correlationId ); } @@ -1813,6 +1821,7 @@ export class StandardController implements IController { ApiId.acquireTokenByCode, this.performanceClient, this.platformAuthProvider, + this.platformAuthType, correlationId ); } @@ -2324,7 +2333,7 @@ export class StandardController implements IController { ): Promise { // if the cache policy is set to access_token only, we should not be hitting the native layer yet if ( - NativeMessageHandler.isPlatformBrokerAvailable( + PlatformAuthProvider.isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, @@ -2347,7 +2356,7 @@ export class StandardController implements IController { "acquireTokenSilent - native platform unavailable, falling back to web flow" ); this.platformAuthProvider = undefined; // Prevent future requests from continuing to attempt - + this.platformAuthType = Constants.EMPTY_STRING; // Cache will not contain tokens, given that previous WAM requests succeeded. Skip cache and RT renewal and go straight to iframe renewal throw createClientAuthError( ClientAuthErrorCodes.tokenRefreshRequired diff --git a/lib/msal-browser/src/index.ts b/lib/msal-browser/src/index.ts index 34b0fc2be5..8c605a473e 100644 --- a/lib/msal-browser/src/index.ts +++ b/lib/msal-browser/src/index.ts @@ -161,4 +161,4 @@ export { export { version } from "./packageMetadata.js"; -export { isPlatformBrokerAvailable } from "./controllers/StandardController.js"; +export { isPlatformBrokerAvailable } from "./broker/nativeBroker/PlatformAuthProvider.js"; diff --git a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts index b8ef74c55e..a82a2695a4 100644 --- a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts @@ -38,6 +38,7 @@ import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandle import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { ClearCacheRequest } from "../request/ClearCacheRequest.js"; import { createNewGuid } from "../crypto/BrowserCrypto.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; export abstract class BaseInteractionClient { protected config: BrowserConfiguration; @@ -47,7 +48,11 @@ export abstract class BaseInteractionClient { protected logger: Logger; protected eventHandler: EventHandler; protected navigationClient: INavigationClient; - protected nativeMessageHandler: NativeMessageHandler | undefined; + protected platformAuthProvider: + | NativeMessageHandler + | PlatformDOMHandler + | undefined; + protected readonly platformAuthType: string | undefined; protected correlationId: string; protected performanceClient: IPerformanceClient; @@ -59,7 +64,8 @@ export abstract class BaseInteractionClient { eventHandler: EventHandler, navigationClient: INavigationClient, performanceClient: IPerformanceClient, - nativeMessageHandler?: NativeMessageHandler, + platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, + platformAuthType?: string, correlationId?: string ) { this.config = config; @@ -68,7 +74,8 @@ export abstract class BaseInteractionClient { this.networkClient = this.config.system.networkClient; this.eventHandler = eventHandler; this.navigationClient = navigationClient; - this.nativeMessageHandler = nativeMessageHandler; + this.platformAuthProvider = platformAuthProvider; + this.platformAuthType = platformAuthType; this.correlationId = correlationId || createNewGuid(); this.logger = logger.clone( BrowserConstants.MSAL_SKU, diff --git a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts index 59ae769391..8b3c6f68a4 100644 --- a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts @@ -56,7 +56,8 @@ import { } from "../utils/BrowserConstants.js"; import { NativeExtensionRequestBody, - NativeTokenRequest, + NativeExtensionTokenRequest, + PlatformDOMTokenRequest, } from "../broker/nativeBroker/NativeRequest.js"; import { MATS, NativeResponse } from "../broker/nativeBroker/NativeResponse.js"; import { @@ -76,11 +77,17 @@ import { SilentCacheClient } from "./SilentCacheClient.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { base64Decode } from "../encode/Base64Decode.js"; import { version } from "../packageMetadata.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { + PLATFORM_DOM_PROVIDER, + PLATFORM_EXTENSION_PROVIDER, +} from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { StringDict } from "../../../msal-common/lib/types/exports-common.js"; export class NativeInteractionClient extends BaseInteractionClient { protected apiId: ApiId; protected accountId: string; - protected nativeMessageHandler: NativeMessageHandler; + protected platformAuthProvider: NativeMessageHandler | PlatformDOMHandler; protected silentCacheClient: SilentCacheClient; protected nativeStorageManager: BrowserCacheManager; protected skus: string; @@ -94,7 +101,8 @@ export class NativeInteractionClient extends BaseInteractionClient { navigationClient: INavigationClient, apiId: ApiId, performanceClient: IPerformanceClient, - provider: NativeMessageHandler, + provider: NativeMessageHandler | PlatformDOMHandler, + platformAuthType: string, accountId: string, nativeStorageImpl: BrowserCacheManager, correlationId?: string @@ -108,11 +116,12 @@ export class NativeInteractionClient extends BaseInteractionClient { navigationClient, performanceClient, provider, + platformAuthType, correlationId ); this.apiId = apiId; this.accountId = accountId; - this.nativeMessageHandler = provider; + this.platformAuthProvider = provider; this.nativeStorageManager = nativeStorageImpl; this.silentCacheClient = new SilentCacheClient( config, @@ -127,26 +136,32 @@ export class NativeInteractionClient extends BaseInteractionClient { ); const extensionName = - this.nativeMessageHandler.getExtensionId() === + this.platformAuthProvider.getExtensionId() === NativeConstants.PREFERRED_EXTENSION_ID ? "chrome" - : this.nativeMessageHandler.getExtensionId()?.length + : this.platformAuthProvider.getExtensionId()?.length ? "unknown" : undefined; + this.skus = ServerTelemetryManager.makeExtraSkuString({ libraryName: BrowserConstants.MSAL_SKU, libraryVersion: version, extensionName: extensionName, - extensionVersion: this.nativeMessageHandler.getExtensionVersion(), + extensionVersion: + this.platformAuthType === PLATFORM_EXTENSION_PROVIDER + ? ( + this.platformAuthProvider as NativeMessageHandler + ).getExtensionVersion() + : undefined, }); } /** * Adds SKUs to request extra query parameters - * @param request {NativeTokenRequest} + * @param request {NativeExtensionTokenRequest} * @private */ - private addRequestSKUs(request: NativeTokenRequest) { + private addRequestSKUs(request: NativeExtensionTokenRequest) { request.extraParameters = { ...request.extraParameters, [AADServerParamKeys.X_CLIENT_EXTRA_SKU]: this.skus, @@ -177,76 +192,99 @@ export class NativeInteractionClient extends BaseInteractionClient { const serverTelemetryManager = this.initializeServerTelemetryManager( this.apiId ); - try { - // initialize native request - const nativeRequest = await this.initializeNativeRequest(request); - // check if the tokens can be retrieved from internal cache + if ( + this.platformAuthType === PLATFORM_EXTENSION_PROVIDER && + this.platformAuthProvider instanceof NativeMessageHandler + ) { try { - const result = await this.acquireTokensFromCache( - this.accountId, - nativeRequest - ); - nativeATMeasurement.end({ - success: true, - isNativeBroker: false, // Should be true only when the result is coming directly from the broker - fromCache: true, - }); - return result; - } catch (e) { - if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) { - this.logger.info( - "MSAL internal Cache does not contain tokens, return error as per cache policy" - ); - throw e; - } - // continue with a native call for any and all errors - this.logger.info( - "MSAL internal Cache does not contain tokens, proceed to make a native call" + // initialize native request + const nativeRequest = await this.initializeNativeRequest( + request ); - } - - const { ...nativeTokenRequest } = nativeRequest; - - // fall back to native calls - const messageBody: NativeExtensionRequestBody = { - method: NativeExtensionMethod.GetToken, - request: nativeTokenRequest, - }; - - const response: object = - await this.nativeMessageHandler.sendMessage(messageBody); - const validatedResponse: NativeResponse = - this.validateNativeResponse(response); - return await this.handleNativeResponse( - validatedResponse, - nativeRequest, - reqTimestamp - ) - .then((result: AuthenticationResult) => { + // check if the tokens can be retrieved from internal cache + try { + const result = await this.acquireTokensFromCache( + this.accountId, + nativeRequest + ); nativeATMeasurement.end({ success: true, - isNativeBroker: true, - requestId: result.requestId, + isNativeBroker: false, // Should be true only when the result is coming directly from the broker + fromCache: true, }); - serverTelemetryManager.clearNativeBrokerErrorCode(); return result; - }) - .catch((error: AuthError) => { - nativeATMeasurement.end({ - success: false, - errorCode: error.errorCode, - subErrorCode: error.subError, - isNativeBroker: true, + } catch (e) { + if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) { + this.logger.info( + "MSAL internal Cache does not contain tokens, return error as per cache policy" + ); + throw e; + } + // continue with a native call for any and all errors + this.logger.info( + "MSAL internal Cache does not contain tokens, proceed to make a native call" + ); + } + + const { ...nativeTokenRequest } = nativeRequest; + + // fall back to native calls + const messageBody: NativeExtensionRequestBody = { + method: NativeExtensionMethod.GetToken, + request: nativeTokenRequest, + }; + + const response: object = + await this.platformAuthProvider.sendMessage(messageBody); + const validatedResponse: NativeResponse = + this.validateNativeResponse(response); + + return await this.handleNativeResponse( + validatedResponse, + nativeRequest, + reqTimestamp + ) + .then((result: AuthenticationResult) => { + nativeATMeasurement.end({ + success: true, + isNativeBroker: true, + requestId: result.requestId, + }); + serverTelemetryManager.clearNativeBrokerErrorCode(); + return result; + }) + .catch((error: AuthError) => { + nativeATMeasurement.end({ + success: false, + errorCode: error.errorCode, + subErrorCode: error.subError, + isNativeBroker: true, + }); + throw error; }); - throw error; - }); - } catch (e) { - if (e instanceof NativeAuthError) { - serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode); + } catch (e) { + if (e instanceof NativeAuthError) { + serverTelemetryManager.setNativeBrokerErrorCode( + e.errorCode + ); + } + throw e; } - throw e; + } else if ( + this.platformAuthType === PLATFORM_DOM_PROVIDER && + this.platformAuthProvider instanceof PlatformDOMHandler + ) { + const nativeRequest = await this.initializeNativeDOMRequest( + request + ); + const response = await ( + this.platformAuthProvider as PlatformDOMHandler + ).sendMessage(nativeRequest); + return response; + } else { + throw "Platform broker unavailable"; } } @@ -257,7 +295,7 @@ export class NativeInteractionClient extends BaseInteractionClient { * @returns CommonSilentFlowRequest */ private createSilentCacheRequest( - request: NativeTokenRequest, + request: NativeExtensionTokenRequest, cachedAccount: AccountInfo ): CommonSilentFlowRequest { return { @@ -277,7 +315,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ protected async acquireTokensFromCache( nativeAccountId: string, - request: NativeTokenRequest + request: NativeExtensionTokenRequest ): Promise { if (!nativeAccountId) { this.logger.warning( @@ -345,8 +383,9 @@ export class NativeInteractionClient extends BaseInteractionClient { }; try { - const response: object = - await this.nativeMessageHandler.sendMessage(messageBody); + const response: object = await ( + this.platformAuthProvider as NativeMessageHandler + ).sendMessage(messageBody); this.validateNativeResponse(response); } catch (e) { // Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise @@ -438,8 +477,9 @@ export class NativeInteractionClient extends BaseInteractionClient { this.logger.verbose( "NativeInteractionClient - handleRedirectPromise sending message to native broker." ); - const response: object = - await this.nativeMessageHandler.sendMessage(messageBody); + const response: object = await ( + this.platformAuthProvider as NativeMessageHandler + ).sendMessage(messageBody); this.validateNativeResponse(response); const result = this.handleNativeResponse( response as NativeResponse, @@ -475,7 +515,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ protected async handleNativeResponse( response: NativeResponse, - request: NativeTokenRequest, + request: NativeExtensionTokenRequest, reqTimestamp: number ): Promise { this.logger.trace( @@ -580,7 +620,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ generateScopes( response: NativeResponse, - request: NativeTokenRequest + request: NativeExtensionTokenRequest ): ScopeSet { return response.scope ? ScopeSet.fromString(response.scope) @@ -594,7 +634,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ async generatePopAccessToken( response: NativeResponse, - request: NativeTokenRequest + request: NativeExtensionTokenRequest ): Promise { if ( request.tokenType === AuthenticationScheme.POP && @@ -653,7 +693,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ protected async generateAuthenticationResult( response: NativeResponse, - request: NativeTokenRequest, + request: NativeExtensionTokenRequest, idTokenClaims: TokenClaims, accountEntity: AccountEntity, authority: string, @@ -754,7 +794,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ cacheNativeTokens( response: NativeResponse, - request: NativeTokenRequest, + request: NativeExtensionTokenRequest, homeAccountIdentifier: string, idTokenClaims: TokenClaims, responseAccessToken: string, @@ -820,9 +860,9 @@ export class NativeInteractionClient extends BaseInteractionClient { this.performanceClient.addFields( { - extensionId: this.nativeMessageHandler.getExtensionId(), + extensionId: this.platformAuthProvider.getExtensionId(), extensionVersion: - this.nativeMessageHandler.getExtensionVersion(), + this.platformAuthProvider.getExtensionVersion(), matsBrokerVersion: mats.broker_version, matsAccountJoinOnStart: mats.account_join_on_start, matsAccountJoinOnEnd: mats.account_join_on_end, @@ -906,79 +946,26 @@ export class NativeInteractionClient extends BaseInteractionClient { */ protected async initializeNativeRequest( request: PopupRequest | SsoSilentRequest - ): Promise { + ): Promise { this.logger.trace( "NativeInteractionClient - initializeNativeRequest called" ); - const requestAuthority = - request.authority || this.config.auth.authority; - - if (request.account) { - // validate authority - await this.getDiscoveredAuthority({ - requestAuthority, - requestAzureCloudOptions: request.azureCloudOptions, - account: request.account, - }); - } - - const canonicalAuthority = new UrlString(requestAuthority); - canonicalAuthority.validateAsUri(); + const canonicalAuthority = await this.getCanonicalAuthority(request); // scopes are expected to be received by the native broker as "scope" and will be added to the request below. Other properties that should be dropped from the request to the native broker can be included in the object destructuring here. const { scopes, ...remainingProperties } = request; const scopeSet = new ScopeSet(scopes || []); scopeSet.appendScopes(OIDC_DEFAULT_SCOPES); - const getPrompt = () => { - // If request is silent, prompt is always none - switch (this.apiId) { - case ApiId.ssoSilent: - case ApiId.acquireTokenSilent_silentFlow: - this.logger.trace( - "initializeNativeRequest: silent request sets prompt to none" - ); - return PromptValue.NONE; - default: - break; - } - - // Prompt not provided, request may proceed and native broker decides if it needs to prompt - if (!request.prompt) { - this.logger.trace( - "initializeNativeRequest: prompt was not provided" - ); - return undefined; - } - - // If request is interactive, check if prompt provided is allowed to go directly to native broker - switch (request.prompt) { - case PromptValue.NONE: - case PromptValue.CONSENT: - case PromptValue.LOGIN: - this.logger.trace( - "initializeNativeRequest: prompt is compatible with native flow" - ); - return request.prompt; - default: - this.logger.trace( - `initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow` - ); - throw createBrowserAuthError( - BrowserAuthErrorCodes.nativePromptNotSupported - ); - } - }; - - const validatedRequest: NativeTokenRequest = { + const validatedRequest: NativeExtensionTokenRequest = { ...remainingProperties, accountId: this.accountId, clientId: this.config.auth.clientId, authority: canonicalAuthority.urlString, scope: scopeSet.printScopes(), redirectUri: this.getRedirectUri(request.redirectUri), - prompt: getPrompt(), + prompt: this.getPrompt(request.prompt), correlationId: this.correlationId, tokenType: request.authenticationScheme, windowTitleSubstring: document.title, @@ -1042,12 +1029,146 @@ export class NativeInteractionClient extends BaseInteractionClient { return validatedRequest; } + protected async initializeNativeDOMRequest( + request: PopupRequest | SilentRequest | SsoSilentRequest + ): Promise { + this.logger.trace( + "NativeInteractionClient: initializeNativeDOMRequest called" + ); + + const canonicalAuthority = await this.getCanonicalAuthority(request); + + const { + correlationId, + redirectUri, + scopes, + state, + extraQueryParameters, + tokenQueryParameters, + ...remainingProperties + } = request; + + delete remainingProperties.authority; + + const scopeSet = new ScopeSet(scopes || []); + scopeSet.appendScopes(OIDC_DEFAULT_SCOPES); + + const tokenType = request.authenticationScheme?.toString() ?? ""; + + const validExtraParameters = { + ...remainingProperties, + ...extraQueryParameters, + ...tokenQueryParameters, + prompt: this.getPrompt(request.prompt) ?? "", + tokenType: tokenType, + windowTitleSubstring: document.title, + }; + + // Convert validExtraParameters to StringDict + const validExtraParametersDict: StringDict = Object.entries( + validExtraParameters + ).reduce((acc, [key, value]) => { + if (typeof value === "string") { + acc[key] = value; + } + return acc; + }, {} as StringDict); + + const nativeRequest: PlatformDOMTokenRequest = { + accountId: this.accountId, + brokerId: ( + this.platformAuthProvider as PlatformDOMHandler + ).getExtensionId(), + authority: canonicalAuthority.urlString, + clientId: this.config.auth.clientId || "", + correlationId: correlationId || this.correlationId, + extraParameters: validExtraParametersDict, + isSecurityTokenService: "true", + redirectUri: this.getRedirectUri(redirectUri), + scope: scopeSet.printScopes(), + state: state, + }; + + this.handleExtraBrokerParams(nativeRequest); + + // Check for PoP token requests: signPopToken should only be set to true if popKid is not set + if (nativeRequest.extraParameters?.signPopToken && !!request.popKid) { + throw createBrowserAuthError( + BrowserAuthErrorCodes.invalidPopTokenRequest + ); + } + + return nativeRequest; + } + + private async getCanonicalAuthority( + request: PopupRequest | SsoSilentRequest + ): Promise { + const requestAuthority = + request.authority || this.config.auth.authority; + + if (request.account) { + // validate authority + await this.getDiscoveredAuthority({ + requestAuthority, + requestAzureCloudOptions: request.azureCloudOptions, + account: request.account, + }); + } + + const canonicalAuthority = new UrlString(requestAuthority); + canonicalAuthority.validateAsUri(); + return canonicalAuthority; + } + + private getPrompt(prompt?: string): string | undefined { + // If request is silent, prompt is always none + switch (this.apiId) { + case ApiId.ssoSilent: + case ApiId.acquireTokenSilent_silentFlow: + this.logger.trace( + "initializeNativeRequest: silent request sets prompt to none" + ); + return PromptValue.NONE; + default: + break; + } + + // Prompt not provided, request may proceed and native broker decides if it needs to prompt + if (!prompt) { + this.logger.trace( + "initializeNativeRequest: prompt was not provided" + ); + return undefined; + } + + // If request is interactive, check if prompt provided is allowed to go directly to native broker + switch (prompt) { + case PromptValue.NONE: + case PromptValue.CONSENT: + case PromptValue.LOGIN: + this.logger.trace( + "initializeNativeRequest: prompt is compatible with native flow" + ); + return prompt; + default: + this.logger.trace( + `initializeNativeRequest: prompt = ${prompt} is not compatible with native flow` + ); + throw createBrowserAuthError( + BrowserAuthErrorCodes.nativePromptNotSupported + ); + } + } + /** * Handles extra broker request parameters - * @param request {NativeTokenRequest} + * @param request {NativeExtensionTokenRequest} * @private */ - private handleExtraBrokerParams(request: NativeTokenRequest): void { + private handleExtraBrokerParams( + request: NativeExtensionTokenRequest | PlatformDOMTokenRequest + ): void { const hasExtraBrokerParams = request.extraParameters && request.extraParameters.hasOwnProperty( diff --git a/lib/msal-browser/src/interaction_client/PopupClient.ts b/lib/msal-browser/src/interaction_client/PopupClient.ts index 45000e201d..2f6d6c6c9d 100644 --- a/lib/msal-browser/src/interaction_client/PopupClient.ts +++ b/lib/msal-browser/src/interaction_client/PopupClient.ts @@ -50,6 +50,8 @@ import { AuthenticationResult } from "../response/AuthenticationResult.js"; import * as ResponseHandler from "../response/ResponseHandler.js"; import { getAuthCodeRequestUrl } from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { PlatformAuthProvider } from "../broker/nativeBroker/PlatformAuthProvider.js"; export type PopupParams = { popup?: Window | null; @@ -71,7 +73,8 @@ export class PopupClient extends StandardInteractionClient { navigationClient: INavigationClient, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - nativeMessageHandler?: NativeMessageHandler, + platformAuthHandler?: NativeMessageHandler | PlatformDOMHandler, + platformAuthType?: string, correlationId?: string ) { super( @@ -82,7 +85,8 @@ export class PopupClient extends StandardInteractionClient { eventHandler, navigationClient, performanceClient, - nativeMessageHandler, + platformAuthHandler, + platformAuthType, correlationId ); // Properly sets this reference for the unload event. @@ -254,13 +258,12 @@ export class PopupClient extends StandardInteractionClient { account: validRequest.account, }); - const isPlatformBroker = - NativeMessageHandler.isPlatformBrokerAvailable( - this.config, - this.logger, - this.nativeMessageHandler, - request.authenticationScheme - ); + const isPlatformBroker = PlatformAuthProvider.isBrokerAvailable( + this.config, + this.logger, + this.platformAuthProvider, + request.authenticationScheme + ); // Start measurement for server calls with native brokering enabled let fetchNativeAccountIdMeasurement; if (isPlatformBroker) { @@ -337,7 +340,7 @@ export class PopupClient extends StandardInteractionClient { }); } - if (!this.nativeMessageHandler) { + if (!this.platformAuthType || !this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); @@ -351,7 +354,8 @@ export class PopupClient extends StandardInteractionClient { this.navigationClient, ApiId.acquireTokenPopup, this.performanceClient, - this.nativeMessageHandler, + this.platformAuthProvider, + this.platformAuthType, serverParams.accountId, this.nativeStorage, validRequest.correlationId diff --git a/lib/msal-browser/src/interaction_client/RedirectClient.ts b/lib/msal-browser/src/interaction_client/RedirectClient.ts index c858b52f97..a67371b9ec 100644 --- a/lib/msal-browser/src/interaction_client/RedirectClient.ts +++ b/lib/msal-browser/src/interaction_client/RedirectClient.ts @@ -50,6 +50,8 @@ import { AuthenticationResult } from "../response/AuthenticationResult.js"; import * as ResponseHandler from "../response/ResponseHandler.js"; import { getAuthCodeRequestUrl } from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { PlatformAuthProvider } from "../broker/nativeBroker/PlatformAuthProvider.js"; function getNavigationType(): NavigationTimingType | undefined { if ( @@ -79,7 +81,8 @@ export class RedirectClient extends StandardInteractionClient { navigationClient: INavigationClient, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - nativeMessageHandler?: NativeMessageHandler, + platformAuthHandler?: NativeMessageHandler | PlatformDOMHandler, + platformAuthType?: string, correlationId?: string ) { super( @@ -90,7 +93,8 @@ export class RedirectClient extends StandardInteractionClient { eventHandler, navigationClient, performanceClient, - nativeMessageHandler, + platformAuthHandler, + platformAuthType, correlationId ); this.nativeStorage = nativeStorageImpl; @@ -185,13 +189,12 @@ export class RedirectClient extends StandardInteractionClient { authClient.authority, { ...validRequest, - platformBroker: - NativeMessageHandler.isPlatformBrokerAvailable( - this.config, - this.logger, - this.nativeMessageHandler, - request.authenticationScheme - ), + platformBroker: PlatformAuthProvider.isBrokerAvailable( + this.config, + this.logger, + this.platformAuthProvider, + request.authenticationScheme + ), }, this.logger, this.performanceClient @@ -473,7 +476,7 @@ export class RedirectClient extends StandardInteractionClient { this.logger.verbose( "Account id found in hash, calling WAM for token" ); - if (!this.nativeMessageHandler) { + if (!this.platformAuthType || !this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); @@ -487,7 +490,8 @@ export class RedirectClient extends StandardInteractionClient { this.navigationClient, ApiId.acquireTokenPopup, this.performanceClient, - this.nativeMessageHandler, + this.platformAuthProvider, + this.platformAuthType, serverParams.accountId, this.nativeStorage, cachedRequest.correlationId diff --git a/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts b/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts index 03af623e61..bac21eeceb 100644 --- a/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts @@ -28,6 +28,7 @@ import { HybridSpaAuthorizationCodeClient } from "./HybridSpaAuthorizationCodeCl import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { InteractionHandler } from "../interaction_handler/InteractionHandler.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; export class SilentAuthCodeClient extends StandardInteractionClient { private apiId: ApiId; @@ -41,7 +42,8 @@ export class SilentAuthCodeClient extends StandardInteractionClient { navigationClient: INavigationClient, apiId: ApiId, performanceClient: IPerformanceClient, - nativeMessageHandler?: NativeMessageHandler, + platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, + platformAuthType?: string, correlationId?: string ) { super( @@ -52,7 +54,8 @@ export class SilentAuthCodeClient extends StandardInteractionClient { eventHandler, navigationClient, performanceClient, - nativeMessageHandler, + platformAuthProvider, + platformAuthType, correlationId ); this.apiId = apiId; diff --git a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts index 7a937bd60b..2b664a8730 100644 --- a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts @@ -44,6 +44,8 @@ import * as BrowserUtils from "../utils/BrowserUtils.js"; import * as ResponseHandler from "../response/ResponseHandler.js"; import { getAuthCodeRequestUrl } from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; +import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { PlatformAuthProvider } from "../broker/nativeBroker/PlatformAuthProvider.js"; export class SilentIframeClient extends StandardInteractionClient { protected apiId: ApiId; @@ -59,7 +61,8 @@ export class SilentIframeClient extends StandardInteractionClient { apiId: ApiId, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - nativeMessageHandler?: NativeMessageHandler, + platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, + platformAuthType?: string, correlationId?: string ) { super( @@ -70,7 +73,8 @@ export class SilentIframeClient extends StandardInteractionClient { eventHandler, navigationClient, performanceClient, - nativeMessageHandler, + platformAuthProvider, + platformAuthType, correlationId ); this.apiId = apiId; @@ -244,10 +248,10 @@ export class SilentIframeClient extends StandardInteractionClient { authClient.authority, { ...silentRequest, - platformBroker: NativeMessageHandler.isPlatformBrokerAvailable( + platformBroker: PlatformAuthProvider.isBrokerAvailable( this.config, this.logger, - this.nativeMessageHandler, + this.platformAuthProvider, silentRequest.authenticationScheme ), }, @@ -298,7 +302,7 @@ export class SilentIframeClient extends StandardInteractionClient { this.logger.verbose( "Account id found in hash, calling WAM for token" ); - if (!this.nativeMessageHandler) { + if (!this.platformAuthType || !this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); @@ -312,7 +316,8 @@ export class SilentIframeClient extends StandardInteractionClient { this.navigationClient, this.apiId, this.performanceClient, - this.nativeMessageHandler, + this.platformAuthProvider, + this.platformAuthType, serverParams.accountId, this.browserStorage, correlationId diff --git a/lib/msal-browser/src/utils/BrowserConstants.ts b/lib/msal-browser/src/utils/BrowserConstants.ts index 0a21cf846d..e0afb2ec11 100644 --- a/lib/msal-browser/src/utils/BrowserConstants.ts +++ b/lib/msal-browser/src/utils/BrowserConstants.ts @@ -45,6 +45,7 @@ export const NativeConstants = { CHANNEL_ID: "53ee284d-920a-4b59-9d30-a60315b26836", PREFERRED_EXTENSION_ID: "ppnbnpeolgkicgegkbkbjmhlideopiji", MATS_TELEMETRY: "MATS", + MICROSOFT_ENTRA_BROKERID: "MicrosoftEntra", }; export const NativeExtensionMethod = { diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 311c156827..fc3e429d2e 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -101,7 +101,7 @@ import { SilentAuthCodeClient } from "../../src/interaction_client/SilentAuthCod import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; -import { NativeTokenRequest } from "../../src/broker/nativeBroker/NativeRequest.js"; +import { NativeExtensionTokenRequest } from "../../src/broker/nativeBroker/NativeRequest.js"; import { NativeAuthError } from "../../src/error/NativeAuthError.js"; import { StandardController } from "../../src/controllers/StandardController.js"; import { AuthenticationResult } from "../../src/response/AuthenticationResult.js"; @@ -719,7 +719,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { fromNativeBroker: true, }; - const nativeRequest: NativeTokenRequest = { + const nativeRequest: NativeExtensionTokenRequest = { authority: TEST_CONFIG.validAuthority, clientId: TEST_CONFIG.MSAL_CLIENT_ID, scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "), @@ -830,7 +830,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { fromNativeBroker: true, }; - const nativeRequest: NativeTokenRequest = { + const nativeRequest: NativeExtensionTokenRequest = { authority: TEST_CONFIG.validAuthority, clientId: TEST_CONFIG.MSAL_CLIENT_ID, scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "), From 1ffd6932fba801a2d96ac590a6c8541bef804259 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 9 Apr 2025 21:31:46 -0700 Subject: [PATCH 06/30] updated StandardController with latest changes --- .../src/controllers/StandardController.ts | 59 +++---------------- 1 file changed, 7 insertions(+), 52 deletions(-) diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 1f4146b16f..387b135bb6 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -45,11 +45,8 @@ import { DEFAULT_REQUEST, BrowserConstants, iFrameRenewalPolicies, -<<<<<<< HEAD NativeConstants, -======= INTERACTION_TYPE, ->>>>>>> d2948772f6632744fbb7aac270f6a5a29f57f338 } from "../utils/BrowserConstants.js"; import * as BrowserUtils from "../utils/BrowserUtils.js"; import { RedirectRequest } from "../request/RedirectRequest.js"; @@ -534,63 +531,21 @@ export class StandardController implements IController { } const loggedInAccounts = this.getAllAccounts(); -<<<<<<< HEAD - const request: NativeExtensionTokenRequest | null = - this.browserStorage.getCachedNativeRequest(); - const useNative = request && this.platformAuthProvider && !hash; - const correlationId = useNative - ? request?.correlationId - : this.browserStorage.getTemporaryCache( - TemporaryCacheKeys.CORRELATION_ID, - true - ) || ""; - const rootMeasurement = this.performanceClient.startMeasurement( - PerformanceEvents.AcquireTokenRedirect, - correlationId - ); -======= - const platformBrokerRequest: NativeTokenRequest | null = + const platformBrokerRequest: NativeExtensionTokenRequest | null = this.browserStorage.getCachedNativeRequest(); const useNative = - platformBrokerRequest && - NativeMessageHandler.isPlatformBrokerAvailable( - this.config, - this.logger, - this.nativeExtensionProvider - ) && - this.nativeExtensionProvider && - !hash; + platformBrokerRequest && this.platformAuthProvider && !hash; + let rootMeasurement: InProgressPerformanceEvent; ->>>>>>> d2948772f6632744fbb7aac270f6a5a29f57f338 + this.eventHandler.emitEvent( EventType.HANDLE_REDIRECT_START, InteractionType.Redirect ); let redirectResponse: Promise; -<<<<<<< HEAD - if (useNative && this.platformAuthProvider) { - this.logger.trace( - "handleRedirectPromise - acquiring token from native platform" - ); - const nativeClient = new NativeInteractionClient( - this.config, - this.browserStorage, - this.browserCrypto, - this.logger, - this.eventHandler, - this.navigationClient, - ApiId.handleRedirectPromise, - this.performanceClient, - this.platformAuthProvider, - this.platformAuthType, - request.accountId, - this.nativeInternalStorage, - request.correlationId - ); -======= try { - if (useNative && this.nativeExtensionProvider) { + if (useNative && this.platformAuthProvider) { rootMeasurement = this.performanceClient.startMeasurement( PerformanceEvents.AcquireTokenRedirect, platformBrokerRequest?.correlationId || "" @@ -607,12 +562,12 @@ export class StandardController implements IController { this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, - this.nativeExtensionProvider, + this.platformAuthProvider, + this.platformAuthType, platformBrokerRequest.accountId, this.nativeInternalStorage, platformBrokerRequest.correlationId ); ->>>>>>> d2948772f6632744fbb7aac270f6a5a29f57f338 redirectResponse = invokeAsync( nativeClient.handleRedirectPromise.bind(nativeClient), From e0c368acfcb871730ee77dc21a0facdc24132f3b Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 23 Apr 2025 10:53:08 -0700 Subject: [PATCH 07/30] native dom api updates --- .../src/broker/nativeBroker/NativeRequest.ts | 2 +- .../src/broker/nativeBroker/NativeResponse.ts | 10 +-- .../nativeBroker/PlatformAuthProvider.ts | 10 +-- .../broker/nativeBroker/PlatformDOMHandler.ts | 72 ++++++++++++++++++- .../src/controllers/StandardController.ts | 8 +-- .../NativeInteractionClient.ts | 27 ++++--- 6 files changed, 97 insertions(+), 32 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts index 0ccce97b96..d2e6606885 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts @@ -61,7 +61,7 @@ export type PlatformDOMTokenRequest = { scope: string; redirectUri: string; correlationId: string; - isSecurityTokenService: string; + isSecurityTokenService: boolean; state?: string; /* * Known optional parameters will go into extraQueryParameters. diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts index 56fd3c6885..624a01df42 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts @@ -62,7 +62,7 @@ export type PlatformDOMResponse = { state?: string; accessToken?: string; expiresIn: number; - account: Account; + account: NativeAccountInfo; clientInfo?: string; idToken?: string; scopes?: string; @@ -78,11 +78,5 @@ export type ErrorResult = { errorCode: string; protocolError?: string; status: string; - properties?: Record; -}; - -export type Account = { - id: string; - userName: string; - properties?: Record; + properties?: object; }; diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 4e929c7060..fc1cb72f23 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -110,10 +110,10 @@ export class PlatformAuthProvider { platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, authenticationScheme?: AuthenticationScheme ): boolean { - logger.trace("isPlatformBrokerAvailable called"); + logger.trace("isBrokerAvailable called"); if (!config.system.allowPlatformBroker) { logger.trace( - "isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false" + "isBrokerAvailable: allowPlatformBroker is not enabled, returning false" ); // Developer disabled WAM return false; @@ -121,7 +121,7 @@ export class PlatformAuthProvider { if (!platformAuthProvider) { logger.trace( - "isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false" + "isBrokerAvailable: Platform extension provider is not initialized, returning false" ); // Extension is not available return false; @@ -132,12 +132,12 @@ export class PlatformAuthProvider { case AuthenticationScheme.BEARER: case AuthenticationScheme.POP: logger.trace( - "isPlatformBrokerAvailable: authenticationScheme is supported, returning true" + "isBrokerAvailable: authenticationScheme is supported, returning true" ); return true; default: logger.trace( - "isPlatformBrokerAvailable: authenticationScheme is not supported, returning false" + "isBrokerAvailable: authenticationScheme is not supported, returning false" ); return false; } diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts index 15dc9d4d5d..7717678cad 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -3,7 +3,16 @@ * Licensed under the MIT License. */ -import { Logger } from "@azure/msal-common"; +import { + /* + * AccountEntity, + * AuthorityType, + * AuthToken, + */ + Constants, + ICrypto, + Logger, +} from "@azure/msal-common"; import { AuthenticationResult } from "../../response/AuthenticationResult.js"; import { PlatformDOMTokenRequest } from "./NativeRequest.js"; import { IPerformanceClient } from "../../../../msal-common/lib/types/exports-browser-only.js"; @@ -11,6 +20,12 @@ import { createNewGuid } from "../../crypto/BrowserCrypto.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; import { ClearCacheRequest } from "../../request/ClearCacheRequest.js"; import { EndSessionRequest } from "../../request/EndSessionRequest.js"; +import { PlatformDOMResponse } from "./NativeResponse.js"; +/* + * import { base64Decode } from "../../encode/Base64Decode.js"; + * import { request } from "http"; + */ +import { AccountInfo } from "../../../../msal-common/lib/types/exports-common.js"; export class PlatformDOMHandler { protected logger: Logger; @@ -18,10 +33,12 @@ export class PlatformDOMHandler { protected correlationId: string; protected extensionId: string; protected extensionVersion: string; + protected browserCrypto: ICrypto; constructor( logger: Logger, performanceClient: IPerformanceClient, + browserCrypto: ICrypto, extensionId?: string, correlationId?: string ) { @@ -30,7 +47,8 @@ export class PlatformDOMHandler { this.extensionId = extensionId || NativeConstants.MICROSOFT_ENTRA_BROKERID; this.correlationId = correlationId || createNewGuid(); - this.extensionVersion = "1.0.0"; + this.extensionVersion = Constants.EMPTY_STRING; + this.browserCrypto = browserCrypto; } /** @@ -64,13 +82,61 @@ export class PlatformDOMHandler { "PlatformDOMHandler: acquireToken response", response ); - return response as AuthenticationResult; + return this.handleNativeResponse(response); } catch (e) { this.logger.error("PlatformDOMHandler: acquireToken error"); throw e; } } + handleNativeResponse(response: PlatformDOMResponse): AuthenticationResult { + this.logger.trace("PlatformDOMHandler: handleNativeResponse called"); + // eslint-disable-next-line no-console + console.log(response); + // generate identifiers + + /* + * if (response.isSuccess) { + * const idTokenClaims = AuthToken.extractTokenClaims( + * response.idToken ?? Constants.EMPTY_STRING, + * base64Decode + * ); + * // Save account in browser storage + * const homeAccountIdentifier = AccountEntity.generateHomeAccountId( + * response.clientInfo || Constants.EMPTY_STRING, + * AuthorityType.Default, + * this.logger, + * this.browserCrypto, + * idTokenClaims + * ); + */ + + /* + * const cachedhomeAccountId = + * this.browserStorage.getAccountInfoFilteredBy({ + * nativeAccountId: request.accountId, + * })?.homeAccountId; + * } + */ + + const authenticationResult: AuthenticationResult = { + authority: "", + uniqueId: "", + tenantId: "", + scopes: [], + idToken: "", + idTokenClaims: {}, + accessToken: "", + fromCache: false, + expiresOn: null, + correlationId: this.correlationId, + tokenType: "", + account: {} as AccountInfo, + }; + + return authenticationResult; + } + logout( // eslint-disable-next-line @typescript-eslint/no-unused-vars request: EndSessionRequest | ClearCacheRequest | undefined diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 387b135bb6..5631e2840a 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -448,6 +448,7 @@ export class StandardController implements IController { return new PlatformDOMHandler( this.logger, this.performanceClient, + this.browserCrypto, NativeConstants.MICROSOFT_ENTRA_BROKERID, correlationId ); @@ -1639,12 +1640,7 @@ export class StandardController implements IController { cacheLookupPolicy?: CacheLookupPolicy ): Promise { this.logger.trace("acquireTokenNative called"); - if (!this.platformAuthType) { - throw createBrowserAuthError( - BrowserAuthErrorCodes.nativeConnectionNotEstablished - ); - } - if (!this.platformAuthProvider) { + if (!this.platformAuthType || !this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); diff --git a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts index 2ad423df45..1846f3f2dd 100644 --- a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts @@ -276,15 +276,24 @@ export class NativeInteractionClient extends BaseInteractionClient { this.platformAuthType === PLATFORM_DOM_PROVIDER && this.platformAuthProvider instanceof PlatformDOMHandler ) { - const nativeRequest = await this.initializeNativeDOMRequest( - request - ); - const response = await ( - this.platformAuthProvider as PlatformDOMHandler - ).sendMessage(nativeRequest); - return response; + try { + const nativeRequest = await this.initializeNativeDOMRequest( + request + ); + const response = await ( + this.platformAuthProvider as PlatformDOMHandler + ).sendMessage(nativeRequest); + return response; + } catch (e) { + if (e instanceof NativeAuthError) { + serverTelemetryManager.setNativeBrokerErrorCode( + e.errorCode + ); + } + throw e; + } } else { - throw "Platform broker unavailable"; + throw "Platform broker unavailable or unrecognized"; } } @@ -1092,7 +1101,7 @@ export class NativeInteractionClient extends BaseInteractionClient { clientId: this.config.auth.clientId || "", correlationId: correlationId || this.correlationId, extraParameters: validExtraParametersDict, - isSecurityTokenService: "true", + isSecurityTokenService: true, redirectUri: this.getRedirectUri(redirectUri), scope: scopeSet.printScopes(), state: state, From 88d9323d9c4abd06c40612fc425609ce9e45a426 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 23 Apr 2025 14:19:05 -0700 Subject: [PATCH 08/30] saving updates --- .../src/broker/nativeBroker/NativeResponse.ts | 2 +- .../nativeBroker/PlatformAuthProvider.ts | 5 +- .../broker/nativeBroker/PlatformDOMHandler.ts | 91 +++++++++++-------- 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts index 624a01df42..5ff1009901 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts @@ -57,7 +57,7 @@ export type MATS = { http_event_count?: number; }; -export type PlatformDOMResponse = { +export type PlatformDOMTokenResponse = { isSuccess: boolean; state?: string; accessToken?: string; diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index fc1cb72f23..71568530d9 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -9,7 +9,7 @@ import { LogLevel, Logger, AuthenticationScheme, -} from "@azure/msal-common"; +} from "@azure/msal-common/browser"; import { name, version } from "../../packageMetadata.js"; import { BrowserConfiguration, @@ -96,6 +96,9 @@ export async function isPlatformBrokerAvailable( } } +/** + * PlatformAuthProvider is a utility class that provides methods to check if the platform broker is available + */ export class PlatformAuthProvider { /** * Returns boolean indicating whether or not the request should attempt to use native broker diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts index 7717678cad..00d80c599d 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -4,15 +4,16 @@ */ import { - /* - * AccountEntity, - * AuthorityType, - * AuthToken, - */ + AccountEntity, + AuthorityType, + AuthToken, Constants, ICrypto, Logger, -} from "@azure/msal-common"; + AccountInfo, + createAuthError, + AuthErrorCodes, +} from "@azure/msal-common/browser"; import { AuthenticationResult } from "../../response/AuthenticationResult.js"; import { PlatformDOMTokenRequest } from "./NativeRequest.js"; import { IPerformanceClient } from "../../../../msal-common/lib/types/exports-browser-only.js"; @@ -20,12 +21,9 @@ import { createNewGuid } from "../../crypto/BrowserCrypto.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; import { ClearCacheRequest } from "../../request/ClearCacheRequest.js"; import { EndSessionRequest } from "../../request/EndSessionRequest.js"; -import { PlatformDOMResponse } from "./NativeResponse.js"; -/* - * import { base64Decode } from "../../encode/Base64Decode.js"; - * import { request } from "http"; - */ -import { AccountInfo } from "../../../../msal-common/lib/types/exports-common.js"; +import { PlatformDOMTokenResponse } from "./NativeResponse.js"; +import { base64Decode } from "../../encode/Base64Decode.js"; +import { BrowserCacheManager } from "../../cache/BrowserCacheManager.js"; export class PlatformDOMHandler { protected logger: Logger; @@ -34,11 +32,13 @@ export class PlatformDOMHandler { protected extensionId: string; protected extensionVersion: string; protected browserCrypto: ICrypto; + protected browserStorage: BrowserCacheManager; constructor( logger: Logger, performanceClient: IPerformanceClient, browserCrypto: ICrypto, + browserStorage: BrowserCacheManager, extensionId?: string, correlationId?: string ) { @@ -49,6 +49,7 @@ export class PlatformDOMHandler { this.correlationId = correlationId || createNewGuid(); this.extensionVersion = Constants.EMPTY_STRING; this.browserCrypto = browserCrypto; + this.browserStorage = browserStorage; } /** @@ -82,42 +83,42 @@ export class PlatformDOMHandler { "PlatformDOMHandler: acquireToken response", response ); - return this.handleNativeResponse(response); + this.validateNativeResponse(response); + return this.handleNativeResponse(request, response); } catch (e) { this.logger.error("PlatformDOMHandler: acquireToken error"); throw e; } } - handleNativeResponse(response: PlatformDOMResponse): AuthenticationResult { + handleNativeResponse( + request: PlatformDOMTokenRequest, + response: PlatformDOMTokenResponse + ): AuthenticationResult { this.logger.trace("PlatformDOMHandler: handleNativeResponse called"); // eslint-disable-next-line no-console console.log(response); // generate identifiers - /* - * if (response.isSuccess) { - * const idTokenClaims = AuthToken.extractTokenClaims( - * response.idToken ?? Constants.EMPTY_STRING, - * base64Decode - * ); - * // Save account in browser storage - * const homeAccountIdentifier = AccountEntity.generateHomeAccountId( - * response.clientInfo || Constants.EMPTY_STRING, - * AuthorityType.Default, - * this.logger, - * this.browserCrypto, - * idTokenClaims - * ); - */ + if (response.isSuccess) { + const idTokenClaims = AuthToken.extractTokenClaims( + response.idToken ?? Constants.EMPTY_STRING, + base64Decode + ); + // Save account in browser storage + const homeAccountIdentifier = AccountEntity.generateHomeAccountId( + response.clientInfo || Constants.EMPTY_STRING, + AuthorityType.Default, + this.logger, + this.browserCrypto, + idTokenClaims + ); - /* - * const cachedhomeAccountId = - * this.browserStorage.getAccountInfoFilteredBy({ - * nativeAccountId: request.accountId, - * })?.homeAccountId; - * } - */ + const cachedhomeAccountId = + this.browserStorage.getAccountInfoFilteredBy({ + nativeAccountId: request.accountId, + })?.homeAccountId; + } const authenticationResult: AuthenticationResult = { authority: "", @@ -144,4 +145,22 @@ export class PlatformDOMHandler { this.logger.trace("PlatformDOMHandler: logout called"); throw new Error("Method not implemented."); } + + private validateNativeResponse(response: object): PlatformDOMTokenResponse { + if ( + response.hasOwnProperty("access_token") && + response.hasOwnProperty("id_token") && + response.hasOwnProperty("client_info") && + response.hasOwnProperty("account") && + response.hasOwnProperty("scope") && + response.hasOwnProperty("expires_in") + ) { + return response as PlatformDOMTokenResponse; + } else { + throw createAuthError( + AuthErrorCodes.unexpectedError, + "Response missing expected properties." + ); + } + } } From 7a29309549552b7635166900afa52581e3f80c01 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 29 Apr 2025 08:41:53 -0700 Subject: [PATCH 09/30] updates to dom native support and added feature flag to enable dom native support --- .../src/app/PublicClientApplication.ts | 27 +- .../nativeBroker/NativeMessageHandler.ts | 2 - .../src/broker/nativeBroker/NativeRequest.ts | 9 +- .../src/broker/nativeBroker/NativeResponse.ts | 12 +- .../broker/nativeBroker/NativeStatusCodes.ts | 4 + .../nativeBroker/PlatformAuthProvider.ts | 2 +- .../broker/nativeBroker/PlatformDOMHandler.ts | 143 ++++---- lib/msal-browser/src/config/FeatureFlags.ts | 19 + .../src/controllers/StandardController.ts | 16 +- lib/msal-browser/src/index.ts | 1 + .../NativeInteractionClient.ts | 340 +++++++++++++++--- .../operatingcontext/BaseOperatingContext.ts | 20 +- 12 files changed, 462 insertions(+), 133 deletions(-) create mode 100644 lib/msal-browser/src/config/FeatureFlags.ts diff --git a/lib/msal-browser/src/app/PublicClientApplication.ts b/lib/msal-browser/src/app/PublicClientApplication.ts index e9b9e8e36f..65e5a9e64d 100644 --- a/lib/msal-browser/src/app/PublicClientApplication.ts +++ b/lib/msal-browser/src/app/PublicClientApplication.ts @@ -35,6 +35,7 @@ import { NestedAppAuthController } from "../controllers/NestedAppAuthController. import { NestedAppOperatingContext } from "../operatingcontext/NestedAppOperatingContext.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { EventType } from "../event/EventType.js"; +import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; /** * The PublicClientApplication class is the object exposed by the library to perform authentication and authorization functions in Single Page Applications @@ -49,12 +50,17 @@ export class PublicClientApplication implements IPublicClientApplication { * @param configuration {Configuration} */ public static async createPublicClientApplication( - configuration: Configuration + configuration: Configuration, + featureSupportConfiguration?: FeatureSupportConfiguration ): Promise { const controller = await ControllerFactory.createV3Controller( configuration ); - const pca = new PublicClientApplication(configuration, controller); + const pca = new PublicClientApplication( + configuration, + featureSupportConfiguration, + controller + ); return pca; } @@ -81,10 +87,19 @@ export class PublicClientApplication implements IPublicClientApplication { * @param configuration Object for the MSAL PublicClientApplication instance * @param IController Optional parameter to explictly set the controller. (Will be removed when we remove public constructor) */ - public constructor(configuration: Configuration, controller?: IController) { + public constructor( + configuration: Configuration, + featureSupportConfiguration?: FeatureSupportConfiguration, + controller?: IController + ) { this.controller = controller || - new StandardController(new StandardOperatingContext(configuration)); + new StandardController( + new StandardOperatingContext( + configuration, + featureSupportConfiguration + ) + ); } /** @@ -439,7 +454,8 @@ export class PublicClientApplication implements IPublicClientApplication { * */ export async function createNestablePublicClientApplication( - configuration: Configuration + configuration: Configuration, + featureSupportConfiguration?: FeatureSupportConfiguration ): Promise { const nestedAppAuth = new NestedAppOperatingContext(configuration); await nestedAppAuth.initialize(); @@ -448,6 +464,7 @@ export async function createNestablePublicClientApplication( const controller = new NestedAppAuthController(nestedAppAuth); const nestablePCA = new PublicClientApplication( configuration, + featureSupportConfiguration, controller ); await nestablePCA.initialize(); diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts index 75a672b4ef..b2b8b3d852 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts @@ -12,7 +12,6 @@ import { AuthError, createAuthError, AuthErrorCodes, - AuthenticationScheme, InProgressPerformanceEvent, PerformanceEvents, IPerformanceClient, @@ -26,7 +25,6 @@ import { createBrowserAuthError, BrowserAuthErrorCodes, } from "../../error/BrowserAuthError.js"; -import { BrowserConfiguration } from "../../config/Configuration.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; type ResponseResolvers = { diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts index d2e6606885..955bb2ae09 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts @@ -67,8 +67,15 @@ export type PlatformDOMTokenRequest = { * Known optional parameters will go into extraQueryParameters. * List of known parameters is: * "prompt", "nonce", "claims", "loginHint", "instanceAware", "windowTitleSubstring", "extendedExpiryToken", "storeInCache", - * PoP related paramters: "reqCnf", "keyId", "tokenType", "shrClaims", "shrNonce", "resourceRequestMethod", "resourceRequestUri", "signPopToken" + * ProofOfPossessionParams: "reqCnf", "keyId", "tokenType", "shrClaims", "shrNonce", "resourceRequestMethod", "resourceRequestUri", "signPopToken" */ extraParameters?: StringDict; embeddedClientId?: string; + storeInCache?: StoreInCache; // Object of booleans indicating whether to store tokens in the cache or not (default is true) +}; + +export type PlatformDOMLogoutRequest = { + brokerId: string; + accountId: string; + extraParameters?: StringDict; }; diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts index 5ff1009901..1faa43f8a4 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. */ -import { AccountInfo } from "@azure/msal-common"; - /** * Account properties returned by Native Platform e.g. WAM */ @@ -61,13 +59,13 @@ export type PlatformDOMTokenResponse = { isSuccess: boolean; state?: string; accessToken?: string; - expiresIn: number; - account: NativeAccountInfo; + expiresIn?: number; + account?: NativeAccountInfo; clientInfo?: string; idToken?: string; scopes?: string; proofOfPossessionPayload?: string; - extendedLifetimeToken: boolean; + extendedLifetimeToken?: boolean; error: ErrorResult; properties?: Record; }; @@ -80,3 +78,7 @@ export type ErrorResult = { status: string; properties?: object; }; + +export type SignOutErrorResult = { + error: ErrorResult; +}; diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts b/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts index a7d42e8ac1..eec25946ab 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts @@ -11,3 +11,7 @@ export const TRANSIENT_ERROR = "TRANSIENT_ERROR"; export const PERSISTENT_ERROR = "PERSISTENT_ERROR"; export const DISABLED = "DISABLED"; export const ACCOUNT_UNAVAILABLE = "ACCOUNT_UNAVAILABLE"; + +// Status codes that can be thrown by the Platform Broker via DOM APIs +export const UI_NOT_ALLOWED = "UI_NOT_ALLOWED"; +export const THROTTLED = "THROTTLED"; diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 71568530d9..8ff2373d97 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -104,7 +104,7 @@ export class PlatformAuthProvider { * Returns boolean indicating whether or not the request should attempt to use native broker * @param logger * @param config - * @param nativeExtensionProvider + * @param platformAuthProvider * @param authenticationScheme */ static isBrokerAvailable( diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts index 00d80c599d..0dd41ee816 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -4,26 +4,26 @@ */ import { - AccountEntity, - AuthorityType, - AuthToken, Constants, ICrypto, Logger, - AccountInfo, createAuthError, AuthErrorCodes, + IPerformanceClient, } from "@azure/msal-common/browser"; -import { AuthenticationResult } from "../../response/AuthenticationResult.js"; -import { PlatformDOMTokenRequest } from "./NativeRequest.js"; -import { IPerformanceClient } from "../../../../msal-common/lib/types/exports-browser-only.js"; +import { + PlatformDOMTokenRequest, + PlatformDOMLogoutRequest, +} from "./NativeRequest.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; -import { ClearCacheRequest } from "../../request/ClearCacheRequest.js"; import { EndSessionRequest } from "../../request/EndSessionRequest.js"; -import { PlatformDOMTokenResponse } from "./NativeResponse.js"; -import { base64Decode } from "../../encode/Base64Decode.js"; +import { + PlatformDOMTokenResponse, + SignOutErrorResult, +} from "./NativeResponse.js"; import { BrowserCacheManager } from "../../cache/BrowserCacheManager.js"; +import { createNativeAuthError } from "../../error/NativeAuthError.js"; export class PlatformDOMHandler { protected logger: Logger; @@ -66,7 +66,7 @@ export class PlatformDOMHandler { async sendMessage( request: PlatformDOMTokenRequest - ): Promise { + ): Promise { this.logger.trace("PlatformDOMHandler: acquireToken called"); try { @@ -78,89 +78,88 @@ export class PlatformDOMHandler { this.logger.trace( "PlatformDOMHandler: acquireToken response received" ); - // NEED TO REMOVE THIS LATER this.logger.trace( "PlatformDOMHandler: acquireToken response", response ); - this.validateNativeResponse(response); - return this.handleNativeResponse(request, response); + return this.validateNativeResponse(response); } catch (e) { - this.logger.error("PlatformDOMHandler: acquireToken error"); - throw e; - } - } - - handleNativeResponse( - request: PlatformDOMTokenRequest, - response: PlatformDOMTokenResponse - ): AuthenticationResult { - this.logger.trace("PlatformDOMHandler: handleNativeResponse called"); - // eslint-disable-next-line no-console - console.log(response); - // generate identifiers - - if (response.isSuccess) { - const idTokenClaims = AuthToken.extractTokenClaims( - response.idToken ?? Constants.EMPTY_STRING, - base64Decode + this.logger.error( + "PlatformDOMHandler: acquireToken platform error" ); - // Save account in browser storage - const homeAccountIdentifier = AccountEntity.generateHomeAccountId( - response.clientInfo || Constants.EMPTY_STRING, - AuthorityType.Default, - this.logger, - this.browserCrypto, - idTokenClaims - ); - - const cachedhomeAccountId = - this.browserStorage.getAccountInfoFilteredBy({ - nativeAccountId: request.accountId, - })?.homeAccountId; + throw e; } - - const authenticationResult: AuthenticationResult = { - authority: "", - uniqueId: "", - tenantId: "", - scopes: [], - idToken: "", - idTokenClaims: {}, - accessToken: "", - fromCache: false, - expiresOn: null, - correlationId: this.correlationId, - tokenType: "", - account: {} as AccountInfo, - }; - - return authenticationResult; } - logout( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - request: EndSessionRequest | ClearCacheRequest | undefined - ): Promise { + async logout(request: EndSessionRequest | undefined): Promise { this.logger.trace("PlatformDOMHandler: logout called"); - throw new Error("Method not implemented."); + const logoutRequest: PlatformDOMLogoutRequest = { + brokerId: this.extensionId, + accountId: + request?.account?.nativeAccountId || Constants.EMPTY_STRING, + extraParameters: request?.extraQueryParameters || {}, + }; + try { + const logoutResponse = + // @ts-ignore + await window.navigator.platformAuthentication.executeSignOut( + logoutRequest + ); + return this.handleLogoutResponse(logoutResponse); + } catch (e) { + this.logger.error("PlatformDOMHandler: platform logout failed"); + throw e; + } } private validateNativeResponse(response: object): PlatformDOMTokenResponse { if ( + response.hasOwnProperty("isSuccess") && response.hasOwnProperty("access_token") && response.hasOwnProperty("id_token") && response.hasOwnProperty("client_info") && response.hasOwnProperty("account") && - response.hasOwnProperty("scope") && + response.hasOwnProperty("scopes") && response.hasOwnProperty("expires_in") ) { return response as PlatformDOMTokenResponse; - } else { - throw createAuthError( - AuthErrorCodes.unexpectedError, - "Response missing expected properties." + } else if ( + response.hasOwnProperty("isSuccess") && + response.hasOwnProperty("error") + ) { + const errorResponse = response as PlatformDOMTokenResponse; + if (errorResponse.isSuccess === false) { + this.logger.trace( + "PlatformDOMHandler: platform broker returned error response" + ); + throw createNativeAuthError( + errorResponse.error.code, + errorResponse.error.description, + { + error: parseInt(errorResponse.error.errorCode), + protocol_error: errorResponse.error.protocolError, + status: errorResponse.error.status, + properties: errorResponse.error.properties, + } + ); + } + } + throw createAuthError( + AuthErrorCodes.unexpectedError, + "Response missing expected properties." + ); + } + + private handleLogoutResponse(logoutResponse: object): void { + if (logoutResponse.hasOwnProperty("error")) { + this.logger.trace("PlatformDOMHandler: logout unsuccessful"); + const logoutErrorResponse = logoutResponse as SignOutErrorResult; + throw createNativeAuthError( + logoutErrorResponse.error.code, + logoutErrorResponse.error.status ); + } else { + this.logger.trace("PlatformDOMHandler: logout successful"); } } } diff --git a/lib/msal-browser/src/config/FeatureFlags.ts b/lib/msal-browser/src/config/FeatureFlags.ts new file mode 100644 index 0000000000..dc6697a234 --- /dev/null +++ b/lib/msal-browser/src/config/FeatureFlags.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +// feature flag configuration for new features in MSAL.js +export type FeatureSupportConfiguration = { + enablePlatformBrokerDOMSupport?: boolean; +}; + +// populate user input or return default values +export function buildFeatureSupportConfiguration( + userInput?: FeatureSupportConfiguration +): FeatureSupportConfiguration { + return { + enablePlatformBrokerDOMSupport: + userInput?.enablePlatformBrokerDOMSupport || false, + }; +} diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 5631e2840a..55e1679dc5 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -94,6 +94,7 @@ import { PLATFORM_EXTENSION_PROVIDER, PlatformAuthProvider, } from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; function getAccountType( account?: AccountInfo @@ -145,6 +146,9 @@ export class StandardController implements IController { // Input configuration by developer/user protected readonly config: BrowserConfiguration; + // Feature support configuration + protected readonly featureSupportConfig: FeatureSupportConfiguration; + // Token cache implementation private tokenCache: TokenCache; @@ -220,6 +224,7 @@ export class StandardController implements IController { this.operatingContext.isBrowserEnvironment(); // Set the configuration. this.config = operatingContext.getConfig(); + this.featureSupportConfig = operatingContext.getFeatureSupportConfig(); this.initialized = false; // Initialize logger @@ -428,8 +433,16 @@ export class StandardController implements IController { ): Promise { this.logger.trace("checkDOMPlatformSupport called", correlationId); + if (!this.featureSupportConfig.enablePlatformBrokerDOMSupport) { + this.logger.trace( + "Platform DOM support is disabled, returning false.", + correlationId + ); + return; + } + if (!this.isBrowserEnvironment) { - this.logger.info("in non-browser environment, returning false."); + this.logger.trace("in non-browser environment, returning false."); return; } @@ -449,6 +462,7 @@ export class StandardController implements IController { this.logger, this.performanceClient, this.browserCrypto, + this.browserStorage, NativeConstants.MICROSOFT_ENTRA_BROKERID, correlationId ); diff --git a/lib/msal-browser/src/index.ts b/lib/msal-browser/src/index.ts index 8c605a473e..f3883845ce 100644 --- a/lib/msal-browser/src/index.ts +++ b/lib/msal-browser/src/index.ts @@ -27,6 +27,7 @@ export { BrowserConfiguration, DEFAULT_IFRAME_TIMEOUT_MS, } from "./config/Configuration.js"; +export { FeatureSupportConfiguration } from "./config/FeatureFlags.js"; export { InteractionType, InteractionStatus, diff --git a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts index 1846f3f2dd..9ff96403d7 100644 --- a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts @@ -59,7 +59,11 @@ import { NativeExtensionTokenRequest, PlatformDOMTokenRequest, } from "../broker/nativeBroker/NativeRequest.js"; -import { MATS, NativeResponse } from "../broker/nativeBroker/NativeResponse.js"; +import { + MATS, + NativeResponse, + PlatformDOMTokenResponse, +} from "../broker/nativeBroker/NativeResponse.js"; import { NativeAuthError, NativeAuthErrorCodes, @@ -139,6 +143,9 @@ export class NativeInteractionClient extends BaseInteractionClient { this.platformAuthProvider.getExtensionId() === NativeConstants.PREFERRED_EXTENSION_ID ? "chrome" + : this.platformAuthProvider.getExtensionId() === + NativeConstants.MICROSOFT_ENTRA_BROKERID + ? NativeConstants.MICROSOFT_ENTRA_BROKERID : this.platformAuthProvider.getExtensionId()?.length ? "unknown" : undefined; @@ -147,12 +154,7 @@ export class NativeInteractionClient extends BaseInteractionClient { libraryName: BrowserConstants.MSAL_SKU, libraryVersion: version, extensionName: extensionName, - extensionVersion: - this.platformAuthType === PLATFORM_EXTENSION_PROVIDER - ? ( - this.platformAuthProvider as NativeMessageHandler - ).getExtensionVersion() - : undefined, + extensionVersion: this.platformAuthProvider.getExtensionVersion(), }); } @@ -161,7 +163,9 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param request {NativeExtensionTokenRequest} * @private */ - private addRequestSKUs(request: NativeExtensionTokenRequest) { + private addRequestSKUs( + request: NativeExtensionTokenRequest | PlatformDOMTokenRequest + ): void { request.extraParameters = { ...request.extraParameters, [AADServerParamKeys.X_CLIENT_EXTRA_SKU]: this.skus, @@ -236,8 +240,9 @@ export class NativeInteractionClient extends BaseInteractionClient { request: nativeTokenRequest, }; - const response: object = - await this.platformAuthProvider.sendMessage(messageBody); + const response: object = await ( + this.platformAuthProvider as NativeMessageHandler + ).sendMessage(messageBody); const validatedResponse: NativeResponse = this.validateNativeResponse(response); @@ -283,7 +288,11 @@ export class NativeInteractionClient extends BaseInteractionClient { const response = await ( this.platformAuthProvider as PlatformDOMHandler ).sendMessage(nativeRequest); - return response; + return await this.handleNativeDOMResponse( + nativeRequest, + response, + reqTimestamp + ); } catch (e) { if (e instanceof NativeAuthError) { serverTelemetryManager.setNativeBrokerErrorCode( @@ -608,6 +617,98 @@ export class NativeInteractionClient extends BaseInteractionClient { return result; } + protected async handleNativeDOMResponse( + request: PlatformDOMTokenRequest, + response: PlatformDOMTokenResponse, + reqTimestamp: number + ): Promise { + this.logger.trace("PlatformDOMHandler: handleNativeDOMResponse called"); + // eslint-disable-next-line no-console + console.log(response); + // generate identifiers + + const idTokenClaims = AuthToken.extractTokenClaims( + response.idToken ?? Constants.EMPTY_STRING, + base64Decode + ); + // Save account in browser storage + const homeAccountIdentifier = AccountEntity.generateHomeAccountId( + response.clientInfo || Constants.EMPTY_STRING, + AuthorityType.Default, + this.logger, + this.browserCrypto, + idTokenClaims + ); + + const cachedhomeAccountId = + this.browserStorage.getAccountInfoFilteredBy({ + nativeAccountId: request.accountId, + })?.homeAccountId; + + // add exception for double brokering, please note this is temporary and will be fortified in future + if ( + request.extraParameters?.child_client_id && + response.account?.id !== request.accountId + ) { + this.logger.info( + "handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch" + ); + } else if ( + homeAccountIdentifier !== cachedhomeAccountId && + response.account?.id !== request.accountId + ) { + // User switch in native broker prompt is not supported. All users must first sign in through web flow to ensure server state is in sync + throw createNativeAuthError(NativeAuthErrorCodes.userSwitch); + } + + // Get the preferred_cache domain for the given authority + const authority = await this.getDiscoveredAuthority({ + requestAuthority: request.authority, + }); + + const baseAccount = buildAccountToCache( + this.browserStorage, + authority, + homeAccountIdentifier, + base64Decode, + idTokenClaims, + response.clientInfo, + undefined, // environment + idTokenClaims.tid, + undefined, // auth code payload + response.account?.id, + this.logger + ); + + // Ensure expires_in is in number format + response.expiresIn = Number(response.expiresIn); + + // generate authenticationResult + const authenticationResult = + await this.generateAuthenticationResultFromDOMResponse( + response, + request, + idTokenClaims, + baseAccount, + authority.canonicalAuthority, + reqTimestamp + ); + + // cache accounts and tokens in the appropriate storage + await this.cacheAccount(baseAccount); + await this.cacheNativeTokens( + response, + request, + homeAccountIdentifier, + idTokenClaims, + response.accessToken || "", + authenticationResult.tenantId, + reqTimestamp + ); + + return authenticationResult; + } + /** * creates an homeAccountIdentifier for the account * @param response @@ -636,13 +737,10 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param request * @returns */ - generateScopes( - response: NativeResponse, - request: NativeExtensionTokenRequest - ): ScopeSet { - return response.scope - ? ScopeSet.fromString(response.scope) - : ScopeSet.fromString(request.scope); + generateScopes(requestScopes: string, responseScopes?: string): ScopeSet { + return responseScopes + ? ScopeSet.fromString(responseScopes) + : ScopeSet.fromString(requestScopes); } /** @@ -718,12 +816,15 @@ export class NativeInteractionClient extends BaseInteractionClient { reqTimestamp: number ): Promise { // Add Native Broker fields to Telemetry - const mats = this.addTelemetryFromNativeResponse(response); + const mats = this.addTelemetryFromNativeResponse( + response.properties.MATS + ); // If scopes not returned in server response, use request scopes - const responseScopes = response.scope - ? ScopeSet.fromString(response.scope) - : ScopeSet.fromString(request.scope); + const responseScopes = this.generateScopes( + request.scope, + response.scope + ); const accountProperties = response.account.properties || {}; const uid = @@ -784,6 +885,91 @@ export class NativeInteractionClient extends BaseInteractionClient { return result; } + /** + * Generates authentication result from DOM response + * @param response + * @param request + * @param idTokenObj + * @param accountEntity + * @param authority + * @param reqTimestamp + * @returns + */ + protected async generateAuthenticationResultFromDOMResponse( + response: PlatformDOMTokenResponse, + request: PlatformDOMTokenRequest, + idTokenClaims: TokenClaims, + accountEntity: AccountEntity, + authority: string, + reqTimestamp: number + ): Promise { + // Add Native Broker fields to Telemetry + const mats = this.addTelemetryFromNativeResponse( + response.properties?.MATS + ); + + // If scopes not returned in server response, use request scopes + const responseScopes = this.generateScopes( + request.scope, + response.scopes + ); + + const accountProperties = response.account?.properties || {}; + const uid = + accountProperties["UID"] || + idTokenClaims.oid || + idTokenClaims.sub || + Constants.EMPTY_STRING; + const tid = + accountProperties["TenantId"] || + idTokenClaims.tid || + Constants.EMPTY_STRING; + + const accountInfo: AccountInfo | null = updateAccountTenantProfileData( + accountEntity.getAccountInfo(), + undefined, // tenantProfile optional + idTokenClaims, + response.idToken + ); + + /** + * In pairwise broker flows, this check prevents the broker's native account id + * from being returned over the embedded app's account id. + */ + if (accountInfo.nativeAccountId !== response.account?.id) { + accountInfo.nativeAccountId = response.account?.id; + } + + // Generate PoP token as needed + const responseAccessToken = response.accessToken; + const tokenType = + request.extraParameters?.tokenType === AuthenticationScheme.POP + ? AuthenticationScheme.POP + : AuthenticationScheme.BEARER; + + const result: AuthenticationResult = { + authority: authority, + uniqueId: uid, + tenantId: tid, + scopes: responseScopes.asArray(), + account: accountInfo, + idToken: response.idToken || "", + idTokenClaims: idTokenClaims, + accessToken: responseAccessToken || "", + fromCache: mats ? this.isResponseFromCache(mats) : false, + // Request timestamp and response expiresIn are in seconds, converting to Date for AuthenticationResult + expiresOn: TimeUtils.toDateFromSeconds( + reqTimestamp + (response.expiresIn || 0) + ), + tokenType: tokenType, + correlationId: this.correlationId, + state: response.state, + fromNativeBroker: true, + }; + + return result; + } + /** * cache the account entity in browser storage * @param accountEntity @@ -811,8 +997,8 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param reqTimestamp */ cacheNativeTokens( - response: NativeResponse, - request: NativeExtensionTokenRequest, + response: NativeResponse | PlatformDOMTokenResponse, + request: NativeExtensionTokenRequest | PlatformDOMTokenRequest, homeAccountIdentifier: string, idTokenClaims: TokenClaims, responseAccessToken: string, @@ -823,20 +1009,29 @@ export class NativeInteractionClient extends BaseInteractionClient { CacheHelpers.createIdTokenEntity( homeAccountIdentifier, request.authority, - response.id_token || "", + (response as NativeResponse).id_token || + (response as PlatformDOMTokenResponse).idToken || + "", request.clientId, idTokenClaims.tid || "" ); // cache accessToken in inmemory storage - const expiresIn: number = - request.tokenType === AuthenticationScheme.POP - ? Constants.SHR_NONCE_VALIDITY - : (typeof response.expires_in === "string" - ? parseInt(response.expires_in, 10) - : response.expires_in) || 0; + const expiresIn: number = this.getExpiresInValue( + (request as NativeExtensionTokenRequest).tokenType || + (request as PlatformDOMTokenRequest).extraParameters + ?.tokenType || + "", + (response as NativeResponse).expires_in || + (response as PlatformDOMTokenResponse).expiresIn + ); + const tokenExpirationSeconds = reqTimestamp + expiresIn; - const responseScopes = this.generateScopes(response, request); + const responseScopes = this.generateScopes( + request.scope, + (response as NativeResponse).scope || + (response as PlatformDOMTokenResponse).scopes + ); const cachedAccessToken: AccessTokenEntity | null = CacheHelpers.createAccessTokenEntity( @@ -850,9 +1045,13 @@ export class NativeInteractionClient extends BaseInteractionClient { 0, base64Decode, undefined, - request.tokenType as AuthenticationScheme, + ((request as NativeExtensionTokenRequest) + .tokenType as AuthenticationScheme) || + ((request as PlatformDOMTokenRequest).extraParameters + ?.tokenType as AuthenticationScheme), undefined, - request.keyId + (request as NativeExtensionTokenRequest).keyId || + (request as PlatformDOMTokenRequest).extraParameters?.keyId ); const nativeCacheRecord = { @@ -867,10 +1066,21 @@ export class NativeInteractionClient extends BaseInteractionClient { ); } + getExpiresInValue( + tokenType: string, + expiresIn: string | number | undefined + ): number { + return tokenType === AuthenticationScheme.POP + ? Constants.SHR_NONCE_VALIDITY + : (typeof expiresIn === "string" + ? parseInt(expiresIn, 10) + : expiresIn) || 0; + } + protected addTelemetryFromNativeResponse( - response: NativeResponse + matsResponse?: string ): MATS | null { - const mats = this.getMATSFromResponse(response); + const mats = this.getMATSFromResponse(matsResponse); if (!mats) { return null; @@ -928,10 +1138,10 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param response * @returns */ - private getMATSFromResponse(response: NativeResponse): MATS | null { - if (response.properties.MATS) { + private getMATSFromResponse(matsResponse: string | undefined): MATS | null { + if (matsResponse) { try { - return JSON.parse(response.properties.MATS); + return JSON.parse(matsResponse); } catch (e) { this.logger.error( "NativeInteractionClient - Error parsing MATS telemetry, returning null instead" @@ -1063,6 +1273,7 @@ export class NativeInteractionClient extends BaseInteractionClient { state, extraQueryParameters, tokenQueryParameters, + storeInCache, ...remainingProperties } = request; @@ -1071,18 +1282,18 @@ export class NativeInteractionClient extends BaseInteractionClient { const scopeSet = new ScopeSet(scopes || []); scopeSet.appendScopes(OIDC_DEFAULT_SCOPES); - const tokenType = request.authenticationScheme?.toString() ?? ""; - const validExtraParameters = { ...remainingProperties, ...extraQueryParameters, ...tokenQueryParameters, - prompt: this.getPrompt(request.prompt) ?? "", - tokenType: tokenType, + prompt: this.getPrompt(request.prompt), + tokenType: request.authenticationScheme, windowTitleSubstring: document.title, + telemetry: NativeConstants.MATS_TELEMETRY, + keyId: request.popKid, }; - // Convert validExtraParameters to StringDict + // Filter and convert validExtraParameters to StringDict const validExtraParametersDict: StringDict = Object.entries( validExtraParameters ).reduce((acc, [key, value]) => { @@ -1105,17 +1316,56 @@ export class NativeInteractionClient extends BaseInteractionClient { redirectUri: this.getRedirectUri(redirectUri), scope: scopeSet.printScopes(), state: state, + storeInCache: storeInCache, }; + nativeRequest.extraParameters = nativeRequest.extraParameters || {}; this.handleExtraBrokerParams(nativeRequest); // Check for PoP token requests: signPopToken should only be set to true if popKid is not set - if (nativeRequest.extraParameters?.signPopToken && !!request.popKid) { + if (nativeRequest.extraParameters.signPopToken && !!request.popKid) { throw createBrowserAuthError( BrowserAuthErrorCodes.invalidPopTokenRequest ); } + if (request.authenticationScheme === AuthenticationScheme.POP) { + // add POP request type + const shrParameters: SignedHttpRequestParameters = { + resourceRequestUri: request.resourceRequestUri, + resourceRequestMethod: request.resourceRequestMethod, + shrClaims: request.shrClaims, + shrNonce: request.shrNonce, + }; + + const popTokenGenerator = new PopTokenGenerator(this.browserCrypto); + + // generate reqCnf if not provided in the request + let reqCnfData; + if (!nativeRequest.extraParameters?.keyId) { + const generatedReqCnfData = await invokeAsync( + popTokenGenerator.generateCnf.bind(popTokenGenerator), + PerformanceEvents.PopTokenGenerateCnf, + this.logger, + this.performanceClient, + request.correlationId + )(shrParameters, this.logger); + reqCnfData = generatedReqCnfData.reqCnfString; + nativeRequest.extraParameters.keyId = generatedReqCnfData.kid; + nativeRequest.extraParameters.signPopToken = "true"; + } else { + reqCnfData = this.browserCrypto.base64UrlEncode( + JSON.stringify({ + kid: nativeRequest.extraParameters?.keyId, + }) + ); + nativeRequest.extraParameters.signPopToken = "false"; + } + + // SPAs require whole string to be passed to broker + nativeRequest.extraParameters.reqCnf = reqCnfData; + } + this.addRequestSKUs(nativeRequest); return nativeRequest; } diff --git a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts index 300259bc9a..670e855f62 100644 --- a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts +++ b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts @@ -15,6 +15,10 @@ import { LOG_LEVEL_CACHE_KEY, LOG_PII_CACHE_KEY, } from "../utils/BrowserConstants.js"; +import { + buildFeatureSupportConfiguration, + FeatureSupportConfiguration, +} from "../config/FeatureFlags.js"; /** * Base class for operating context @@ -28,6 +32,7 @@ export abstract class BaseOperatingContext { protected config: BrowserConfiguration; protected available: boolean; protected browserEnvironment: boolean; + protected featureSupportConfig: FeatureSupportConfiguration; protected static loggerCallback(level: LogLevel, message: string): void { switch (level) { @@ -54,7 +59,10 @@ export abstract class BaseOperatingContext { } } - constructor(config: Configuration) { + constructor( + config: Configuration, + featureSupportConfig?: FeatureSupportConfiguration + ) { /* * If loaded in an environment where window is not available, * set internal flag to false so that further requests fail. @@ -62,6 +70,8 @@ export abstract class BaseOperatingContext { */ this.browserEnvironment = typeof window !== "undefined"; this.config = buildConfiguration(config, this.browserEnvironment); + this.featureSupportConfig = + buildFeatureSupportConfiguration(featureSupportConfig); let sessionStorage: Storage | undefined; try { @@ -121,6 +131,14 @@ export abstract class BaseOperatingContext { return this.config; } + /** + * Return MSAL config for enabled features + * @returns FeatureSupportConfiguration + */ + getFeatureSupportConfig(): FeatureSupportConfiguration { + return this.featureSupportConfig; + } + /** * Returns the MSAL Logger * @returns Logger From ecf1b3a56578d6e2966bf4c5c9fb4b51b913e30c Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Thu, 1 May 2025 09:45:32 -0700 Subject: [PATCH 10/30] refactoring NativeInteractionClient and addressing some comments --- .../nativeBroker/NativeMessageHandler.ts | 48 +- .../src/broker/nativeBroker/NativeRequest.ts | 10 +- .../src/broker/nativeBroker/NativeResponse.ts | 18 +- .../nativeBroker/PlatformAuthProvider.ts | 108 ++-- .../broker/nativeBroker/PlatformDOMHandler.ts | 226 ++++--- .../src/cache/BrowserCacheManager.ts | 6 +- .../src/controllers/StandardController.ts | 19 +- .../NativeInteractionClient.ts | 568 +++--------------- .../src/interaction_client/PopupClient.ts | 4 +- .../src/interaction_client/RedirectClient.ts | 4 +- .../interaction_client/SilentIframeClient.ts | 4 +- .../test/app/PublicClientApplication.spec.ts | 6 +- .../test/utils/StringConstants.ts | 45 ++ 13 files changed, 392 insertions(+), 674 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts index b2b8b3d852..8a77a59473 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts @@ -19,6 +19,7 @@ import { import { NativeExtensionRequest, NativeExtensionRequestBody, + PlatformBrokerRequest, } from "./NativeRequest.js"; import { createNativeAuthError } from "../../error/NativeAuthError.js"; import { @@ -26,6 +27,7 @@ import { BrowserAuthErrorCodes, } from "../../error/BrowserAuthError.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; +import { PlatformBrokerResponse } from "./NativeResponse.js"; type ResponseResolvers = { resolve: (value: T | PromiseLike) => void; @@ -68,15 +70,26 @@ export class NativeMessageHandler { /** * Sends a given message to the extension and resolves with the extension response - * @param body + * @param request */ - async sendMessage(body: NativeExtensionRequestBody): Promise { + async sendMessage( + request: PlatformBrokerRequest + ): Promise { this.logger.trace("NativeMessageHandler - sendMessage called."); + + const { ...nativeTokenRequest } = request; + + // fall back to native calls + const messageBody: NativeExtensionRequestBody = { + method: NativeExtensionMethod.GetToken, + request: nativeTokenRequest, + }; + const req: NativeExtensionRequest = { channel: NativeConstants.CHANNEL_ID, extensionId: this.extensionId, responseId: createNewGuid(), - body: body, + body: messageBody, }; this.logger.trace( @@ -89,9 +102,14 @@ export class NativeMessageHandler { ); this.messageChannel.port1.postMessage(req); - return new Promise((resolve, reject) => { + const response: object = await new Promise((resolve, reject) => { this.resolvers.set(req.responseId, { resolve, reject }); }); + + const validatedResponse: PlatformBrokerResponse = + this.validateNativeResponse(response); + + return validatedResponse; } /** @@ -347,6 +365,28 @@ export class NativeMessageHandler { } } + /** + * Validates native platform response before processing + * @param response + */ + private validateNativeResponse(response: object): PlatformBrokerResponse { + if ( + response.hasOwnProperty("access_token") && + response.hasOwnProperty("id_token") && + response.hasOwnProperty("client_info") && + response.hasOwnProperty("account") && + response.hasOwnProperty("scope") && + response.hasOwnProperty("expires_in") + ) { + return response as PlatformBrokerResponse; + } else { + throw createAuthError( + AuthErrorCodes.unexpectedError, + "Response missing expected properties." + ); + } + } + /** * Returns the Id for the browser extension this handler is communicating with * @returns diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts index 955bb2ae09..7aa143f156 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts @@ -9,7 +9,7 @@ import { StoreInCache, StringDict } from "@azure/msal-common/browser"; /** * Token request which native broker will use to acquire tokens */ -export type NativeExtensionTokenRequest = { +export type PlatformBrokerRequest = { accountId: string; // WAM specific account id used for identification of WAM account. This can be any broker-id eventually clientId: string; authority: string; @@ -40,7 +40,7 @@ export type NativeExtensionTokenRequest = { */ export type NativeExtensionRequestBody = { method: NativeExtensionMethod; - request?: NativeExtensionTokenRequest; + request?: PlatformBrokerRequest; }; /** @@ -73,9 +73,3 @@ export type PlatformDOMTokenRequest = { embeddedClientId?: string; storeInCache?: StoreInCache; // Object of booleans indicating whether to store tokens in the cache or not (default is true) }; - -export type PlatformDOMLogoutRequest = { - brokerId: string; - accountId: string; - extraParameters?: StringDict; -}; diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts index 1faa43f8a4..fb2e87f96f 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts @@ -15,7 +15,7 @@ export type NativeAccountInfo = { /** * Token response returned by Native Platform */ -export type NativeResponse = { +export type PlatformBrokerResponse = { access_token: string; account: NativeAccountInfo; client_info: string; @@ -58,12 +58,12 @@ export type MATS = { export type PlatformDOMTokenResponse = { isSuccess: boolean; state?: string; - accessToken?: string; - expiresIn?: number; - account?: NativeAccountInfo; - clientInfo?: string; - idToken?: string; - scopes?: string; + accessToken: string; + expiresIn: number; + account: NativeAccountInfo; + clientInfo: string; + idToken: string; + scopes: string; proofOfPossessionPayload?: string; extendedLifetimeToken?: boolean; error: ErrorResult; @@ -78,7 +78,3 @@ export type ErrorResult = { status: string; properties?: object; }; - -export type SignOutErrorResult = { - error: ErrorResult; -}; diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 8ff2373d97..56580f9671 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -6,7 +6,6 @@ import { LoggerOptions, IPerformanceClient, - LogLevel, Logger, AuthenticationScheme, } from "@azure/msal-common/browser"; @@ -23,23 +22,17 @@ import { PlatformDOMHandler } from "./PlatformDOMHandler.js"; export const PLATFORM_EXTENSION_PROVIDER = "NativeMessageHandler"; export const PLATFORM_DOM_PROVIDER = "PlatformDOMHandler"; +/** + * Checks if the platform broker is available in the current environment. + * @param loggerOptions + * @param perfClient + * @returns + */ export async function isPlatformBrokerAvailable( loggerOptions?: LoggerOptions, perfClient?: IPerformanceClient ): Promise { - const defaultLoggerOptions: LoggerOptions = { - loggerCallback: (): void => { - // Empty logger callback - }, - piiLoggingEnabled: false, - logLevel: LogLevel.Trace, - }; - - const logger = new Logger( - loggerOptions || defaultLoggerOptions, - name, - version - ); + const logger = new Logger(loggerOptions || {}, name, version); logger.trace("isPlatformBrokerAvailable called"); @@ -97,55 +90,50 @@ export async function isPlatformBrokerAvailable( } /** - * PlatformAuthProvider is a utility class that provides methods to check if the platform broker is available + * Returns boolean indicating whether or not the request should attempt to use native broker + * @param logger + * @param config + * @param platformAuthProvider + * @param authenticationScheme */ -export class PlatformAuthProvider { - /** - * Returns boolean indicating whether or not the request should attempt to use native broker - * @param logger - * @param config - * @param platformAuthProvider - * @param authenticationScheme - */ - static isBrokerAvailable( - config: BrowserConfiguration, - logger: Logger, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - authenticationScheme?: AuthenticationScheme - ): boolean { - logger.trace("isBrokerAvailable called"); - if (!config.system.allowPlatformBroker) { - logger.trace( - "isBrokerAvailable: allowPlatformBroker is not enabled, returning false" - ); - // Developer disabled WAM - return false; - } +export function isBrokerAvailable( + config: BrowserConfiguration, + logger: Logger, + platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, + authenticationScheme?: AuthenticationScheme +): boolean { + logger.trace("isBrokerAvailable called"); + if (!config.system.allowPlatformBroker) { + logger.trace( + "isBrokerAvailable: allowPlatformBroker is not enabled, returning false" + ); + // Developer disabled WAM + return false; + } - if (!platformAuthProvider) { - logger.trace( - "isBrokerAvailable: Platform extension provider is not initialized, returning false" - ); - // Extension is not available - return false; - } + if (!platformAuthProvider) { + logger.trace( + "isBrokerAvailable: Platform auth provider is not initialized, returning false" + ); + // Extension is not available + return false; + } - if (authenticationScheme) { - switch (authenticationScheme) { - case AuthenticationScheme.BEARER: - case AuthenticationScheme.POP: - logger.trace( - "isBrokerAvailable: authenticationScheme is supported, returning true" - ); - return true; - default: - logger.trace( - "isBrokerAvailable: authenticationScheme is not supported, returning false" - ); - return false; - } + if (authenticationScheme) { + switch (authenticationScheme) { + case AuthenticationScheme.BEARER: + case AuthenticationScheme.POP: + logger.trace( + "isBrokerAvailable: authenticationScheme is supported, returning true" + ); + return true; + default: + logger.trace( + "isBrokerAvailable: authenticationScheme is not supported, returning false" + ); + return false; } - - return true; } + + return true; } diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts index 0dd41ee816..535722cf8b 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -4,144 +4,173 @@ */ import { - Constants, - ICrypto, Logger, createAuthError, AuthErrorCodes, IPerformanceClient, + StringDict, } from "@azure/msal-common/browser"; import { + PlatformBrokerRequest, PlatformDOMTokenRequest, - PlatformDOMLogoutRequest, } from "./NativeRequest.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; -import { EndSessionRequest } from "../../request/EndSessionRequest.js"; import { + PlatformBrokerResponse, PlatformDOMTokenResponse, - SignOutErrorResult, } from "./NativeResponse.js"; -import { BrowserCacheManager } from "../../cache/BrowserCacheManager.js"; import { createNativeAuthError } from "../../error/NativeAuthError.js"; export class PlatformDOMHandler { protected logger: Logger; protected performanceClient: IPerformanceClient; protected correlationId: string; - protected extensionId: string; + protected brokerId: string; protected extensionVersion: string; - protected browserCrypto: ICrypto; - protected browserStorage: BrowserCacheManager; constructor( logger: Logger, performanceClient: IPerformanceClient, - browserCrypto: ICrypto, - browserStorage: BrowserCacheManager, - extensionId?: string, + brokerId?: string, correlationId?: string ) { this.logger = logger; this.performanceClient = performanceClient; - this.extensionId = - extensionId || NativeConstants.MICROSOFT_ENTRA_BROKERID; + this.brokerId = brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID; this.correlationId = correlationId || createNewGuid(); - this.extensionVersion = Constants.EMPTY_STRING; - this.browserCrypto = browserCrypto; - this.browserStorage = browserStorage; + this.extensionVersion = ""; } /** - * Returns the Id for the browser extension this handler is communicating with + * Returns the Id for the broker extension this handler is communicating with * @returns */ getExtensionId(): string { - return this.extensionId; + return this.brokerId; } + /** + * Gets the version of the browser this handler is communicating with + */ getExtensionVersion(): string | undefined { + // @ts-ignore + const userAgent = window.navigator.userAgentData?.getHighEntropyValues([ + "uaFullVersion", + ]); + this.extensionVersion = userAgent ? userAgent["uaFullVersion"] : ""; return this.extensionVersion; } + /** + * Send token request to platform broker via browser DOM API + * @param request + * @returns + */ async sendMessage( - request: PlatformDOMTokenRequest - ): Promise { - this.logger.trace("PlatformDOMHandler: acquireToken called"); + request: PlatformBrokerRequest + ): Promise { + this.logger.trace( + "PlatformDOMHandler - Sending request to browser DOM API" + ); + this.logger.tracePii( + `PlatformDOMHandler - Sending request to browser DOM API: ${JSON.stringify( + request + )}` + ); try { - const response = + const platformDOMRequest: PlatformDOMTokenRequest = + await this.initializePlatformDOMRequest(request); + const response: object = // @ts-ignore await window.navigator.platformAuthentication.executeGetToken( - request + platformDOMRequest ); - this.logger.trace( - "PlatformDOMHandler: acquireToken response received" - ); - this.logger.trace( - "PlatformDOMHandler: acquireToken response", - response - ); - return this.validateNativeResponse(response); + const validatedResponse: PlatformDOMTokenResponse = + this.validateNativeResponse(response); + return this.convertToNativeResponse(validatedResponse); } catch (e) { this.logger.error( - "PlatformDOMHandler: acquireToken platform error" + "PlatformDOMHandler: executeGetToken DOM API error" ); throw e; } } - async logout(request: EndSessionRequest | undefined): Promise { - this.logger.trace("PlatformDOMHandler: logout called"); - const logoutRequest: PlatformDOMLogoutRequest = { - brokerId: this.extensionId, - accountId: - request?.account?.nativeAccountId || Constants.EMPTY_STRING, - extraParameters: request?.extraQueryParameters || {}, + private async initializePlatformDOMRequest( + request: PlatformBrokerRequest + ): Promise { + this.logger.trace( + "NativeInteractionClient: initializeNativeDOMRequest called" + ); + + const { + accountId, + clientId, + authority, + scope, + redirectUri, + correlationId, + state, + storeInCache, + embeddedClientId, + extraParameters, + ...remainingProperties + } = request; + + const validExtraParameters = + this.stringifyExtraParameters(remainingProperties); + + const platformDOMRequest: PlatformDOMTokenRequest = { + accountId: accountId, + brokerId: this.getExtensionId(), + authority: authority, + clientId: clientId, + correlationId: correlationId || this.correlationId, + extraParameters: { ...extraParameters, ...validExtraParameters }, + isSecurityTokenService: true, + redirectUri: redirectUri, + scope: scope, + state: state, + storeInCache: storeInCache, + embeddedClientId: embeddedClientId, }; - try { - const logoutResponse = - // @ts-ignore - await window.navigator.platformAuthentication.executeSignOut( - logoutRequest - ); - return this.handleLogoutResponse(logoutResponse); - } catch (e) { - this.logger.error("PlatformDOMHandler: platform logout failed"); - throw e; - } + + return platformDOMRequest; } private validateNativeResponse(response: object): PlatformDOMTokenResponse { - if ( - response.hasOwnProperty("isSuccess") && - response.hasOwnProperty("access_token") && - response.hasOwnProperty("id_token") && - response.hasOwnProperty("client_info") && - response.hasOwnProperty("account") && - response.hasOwnProperty("scopes") && - response.hasOwnProperty("expires_in") - ) { - return response as PlatformDOMTokenResponse; - } else if ( - response.hasOwnProperty("isSuccess") && - response.hasOwnProperty("error") - ) { - const errorResponse = response as PlatformDOMTokenResponse; - if (errorResponse.isSuccess === false) { + if (response.hasOwnProperty("isSuccess")) { + if ( + response.hasOwnProperty("access_token") && + response.hasOwnProperty("id_token") && + response.hasOwnProperty("client_info") && + response.hasOwnProperty("account") && + response.hasOwnProperty("scopes") && + response.hasOwnProperty("expires_in") + ) { this.logger.trace( - "PlatformDOMHandler: platform broker returned error response" - ); - throw createNativeAuthError( - errorResponse.error.code, - errorResponse.error.description, - { - error: parseInt(errorResponse.error.errorCode), - protocol_error: errorResponse.error.protocolError, - status: errorResponse.error.status, - properties: errorResponse.error.properties, - } + "PlatformDOMHandler: platform broker returned successful and valid response" ); + return response as PlatformDOMTokenResponse; + } else if (response.hasOwnProperty("error")) { + const errorResponse = response as PlatformDOMTokenResponse; + if (errorResponse.isSuccess === false) { + this.logger.trace( + "PlatformDOMHandler: platform broker returned error response" + ); + throw createNativeAuthError( + errorResponse.error.code, + errorResponse.error.description, + { + error: parseInt(errorResponse.error.errorCode), + protocol_error: errorResponse.error.protocolError, + status: errorResponse.error.status, + properties: errorResponse.error.properties, + } + ); + } } } throw createAuthError( @@ -150,16 +179,35 @@ export class PlatformDOMHandler { ); } - private handleLogoutResponse(logoutResponse: object): void { - if (logoutResponse.hasOwnProperty("error")) { - this.logger.trace("PlatformDOMHandler: logout unsuccessful"); - const logoutErrorResponse = logoutResponse as SignOutErrorResult; - throw createNativeAuthError( - logoutErrorResponse.error.code, - logoutErrorResponse.error.status - ); - } else { - this.logger.trace("PlatformDOMHandler: logout successful"); - } + private convertToNativeResponse( + response: PlatformDOMTokenResponse + ): PlatformBrokerResponse { + this.logger.trace("PlatformDOMHandler: convertToNativeResponse called"); + const nativeResponse: PlatformBrokerResponse = { + access_token: response.accessToken, + id_token: response.idToken, + client_info: response.clientInfo, + account: response.account, + expires_in: response.expiresIn, + scope: response.scopes, + state: response.state || "", + properties: response.properties || {}, + extendedLifetimeToken: response.extendedLifetimeToken, + shr: response.proofOfPossessionPayload, + }; + + return nativeResponse; + } + + private stringifyExtraParameters( + extraParameters: Record + ): StringDict { + return Object.entries(extraParameters).reduce( + (record, [key, value]) => { + record[key] = String(value); + return record; + }, + {} as StringDict + ); } } diff --git a/lib/msal-browser/src/cache/BrowserCacheManager.ts b/lib/msal-browser/src/cache/BrowserCacheManager.ts index 0b36cb733e..8aa7d42f55 100644 --- a/lib/msal-browser/src/cache/BrowserCacheManager.ts +++ b/lib/msal-browser/src/cache/BrowserCacheManager.ts @@ -53,7 +53,7 @@ import { LocalStorage } from "./LocalStorage.js"; import { SessionStorage } from "./SessionStorage.js"; import { MemoryStorage } from "./MemoryStorage.js"; import { IWindowStorage } from "./IWindowStorage.js"; -import { NativeExtensionTokenRequest } from "../broker/nativeBroker/NativeRequest.js"; +import { PlatformBrokerRequest } from "../broker/nativeBroker/NativeRequest.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { SilentRequest } from "../request/SilentRequest.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; @@ -1161,7 +1161,7 @@ export class BrowserCacheManager extends CacheManager { /** * Gets cached native request for redirect flows */ - getCachedNativeRequest(): NativeExtensionTokenRequest | null { + getCachedNativeRequest(): PlatformBrokerRequest | null { this.logger.trace("BrowserCacheManager.getCachedNativeRequest called"); const cachedRequest = this.getTemporaryCache( TemporaryCacheKeys.NATIVE_REQUEST, @@ -1176,7 +1176,7 @@ export class BrowserCacheManager extends CacheManager { const parsedRequest = this.validateAndParseJson( cachedRequest - ) as NativeExtensionTokenRequest; + ) as PlatformBrokerRequest; if (!parsedRequest) { this.logger.error( "BrowserCacheManager.getCachedNativeRequest: Unable to parse native request" diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 55e1679dc5..c53412506d 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -78,7 +78,7 @@ import { BrowserAuthErrorCodes, } from "../error/BrowserAuthError.js"; import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js"; -import { NativeExtensionTokenRequest } from "../broker/nativeBroker/NativeRequest.js"; +import { PlatformBrokerRequest } from "../broker/nativeBroker/NativeRequest.js"; import { StandardOperatingContext } from "../operatingcontext/StandardOperatingContext.js"; import { BaseOperatingContext } from "../operatingcontext/BaseOperatingContext.js"; import { IController } from "./IController.js"; @@ -90,9 +90,9 @@ import { InitializeApplicationRequest } from "../request/InitializeApplicationRe import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; import { + isBrokerAvailable, PLATFORM_DOM_PROVIDER, PLATFORM_EXTENSION_PROVIDER, - PlatformAuthProvider, } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; @@ -429,7 +429,8 @@ export class StandardController implements IController { } protected async checkDOMPlatformSupport( - correlationId?: string + correlationId?: string, + brokerId?: string ): Promise { this.logger.trace("checkDOMPlatformSupport called", correlationId); @@ -451,7 +452,7 @@ export class StandardController implements IController { const supportedContracts = // @ts-ignore await window.navigator.platformAuthentication.getSupportedContracts( - NativeConstants.MICROSOFT_ENTRA_BROKERID + brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID ); if (supportedContracts.includes("get-token-and-sign-out")) { this.logger.trace( @@ -461,9 +462,7 @@ export class StandardController implements IController { return new PlatformDOMHandler( this.logger, this.performanceClient, - this.browserCrypto, - this.browserStorage, - NativeConstants.MICROSOFT_ENTRA_BROKERID, + brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID, correlationId ); } @@ -546,7 +545,7 @@ export class StandardController implements IController { } const loggedInAccounts = this.getAllAccounts(); - const platformBrokerRequest: NativeExtensionTokenRequest | null = + const platformBrokerRequest: PlatformBrokerRequest | null = this.browserStorage.getCachedNativeRequest(); const useNative = platformBrokerRequest && this.platformAuthProvider && !hash; @@ -1696,7 +1695,7 @@ export class StandardController implements IController { } if ( - !PlatformAuthProvider.isBrokerAvailable( + !isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, @@ -2385,7 +2384,7 @@ export class StandardController implements IController { ): Promise { // if the cache policy is set to access_token only, we should not be hitting the native layer yet if ( - PlatformAuthProvider.isBrokerAvailable( + isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, diff --git a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts index 9ff96403d7..92e1c1a10a 100644 --- a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts @@ -30,8 +30,6 @@ import { createClientAuthError, ClientAuthErrorCodes, invokeAsync, - createAuthError, - AuthErrorCodes, updateAccountTenantProfileData, CacheHelpers, buildAccountToCache, @@ -47,7 +45,6 @@ import { SilentRequest } from "../request/SilentRequest.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { - NativeExtensionMethod, ApiId, TemporaryCacheKeys, NativeConstants, @@ -55,14 +52,12 @@ import { CacheLookupPolicy, } from "../utils/BrowserConstants.js"; import { - NativeExtensionRequestBody, - NativeExtensionTokenRequest, + PlatformBrokerRequest, PlatformDOMTokenRequest, } from "../broker/nativeBroker/NativeRequest.js"; import { MATS, - NativeResponse, - PlatformDOMTokenResponse, + PlatformBrokerResponse, } from "../broker/nativeBroker/NativeResponse.js"; import { NativeAuthError, @@ -82,11 +77,6 @@ import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { base64Decode } from "../encode/Base64Decode.js"; import { version } from "../packageMetadata.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; -import { - PLATFORM_DOM_PROVIDER, - PLATFORM_EXTENSION_PROVIDER, -} from "../broker/nativeBroker/PlatformAuthProvider.js"; -import { StringDict } from "../../../msal-common/lib/types/exports-common.js"; export class NativeInteractionClient extends BaseInteractionClient { protected apiId: ApiId; @@ -160,11 +150,11 @@ export class NativeInteractionClient extends BaseInteractionClient { /** * Adds SKUs to request extra query parameters - * @param request {NativeExtensionTokenRequest} + * @param request {PlatformBrokerRequest} * @private */ private addRequestSKUs( - request: NativeExtensionTokenRequest | PlatformDOMTokenRequest + request: PlatformBrokerRequest | PlatformDOMTokenRequest ): void { request.extraParameters = { ...request.extraParameters, @@ -197,112 +187,66 @@ export class NativeInteractionClient extends BaseInteractionClient { this.apiId ); - if ( - this.platformAuthType === PLATFORM_EXTENSION_PROVIDER && - this.platformAuthProvider instanceof NativeMessageHandler - ) { + try { + // initialize native request + const nativeRequest = await this.initializeNativeRequest(request); + + // check if the tokens can be retrieved from internal cache try { - // initialize native request - const nativeRequest = await this.initializeNativeRequest( - request + const result = await this.acquireTokensFromCache( + this.accountId, + nativeRequest ); - - // check if the tokens can be retrieved from internal cache - try { - const result = await this.acquireTokensFromCache( - this.accountId, - nativeRequest + nativeATMeasurement.end({ + success: true, + isNativeBroker: false, // Should be true only when the result is coming directly from the broker + fromCache: true, + }); + return result; + } catch (e) { + if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) { + this.logger.info( + "MSAL internal Cache does not contain tokens, return error as per cache policy" ); + throw e; + } + // continue with a native call for any and all errors + this.logger.info( + "MSAL internal Cache does not contain tokens, proceed to make a native call" + ); + } + + const validatedResponse: PlatformBrokerResponse = + await this.platformAuthProvider.sendMessage(nativeRequest); + + return await this.handleNativeResponse( + validatedResponse, + nativeRequest, + reqTimestamp + ) + .then((result: AuthenticationResult) => { nativeATMeasurement.end({ success: true, - isNativeBroker: false, // Should be true only when the result is coming directly from the broker - fromCache: true, + isNativeBroker: true, + requestId: result.requestId, }); + serverTelemetryManager.clearNativeBrokerErrorCode(); return result; - } catch (e) { - if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) { - this.logger.info( - "MSAL internal Cache does not contain tokens, return error as per cache policy" - ); - throw e; - } - // continue with a native call for any and all errors - this.logger.info( - "MSAL internal Cache does not contain tokens, proceed to make a native call" - ); - } - - const { ...nativeTokenRequest } = nativeRequest; - - // fall back to native calls - const messageBody: NativeExtensionRequestBody = { - method: NativeExtensionMethod.GetToken, - request: nativeTokenRequest, - }; - - const response: object = await ( - this.platformAuthProvider as NativeMessageHandler - ).sendMessage(messageBody); - const validatedResponse: NativeResponse = - this.validateNativeResponse(response); - - return await this.handleNativeResponse( - validatedResponse, - nativeRequest, - reqTimestamp - ) - .then((result: AuthenticationResult) => { - nativeATMeasurement.end({ - success: true, - isNativeBroker: true, - requestId: result.requestId, - }); - serverTelemetryManager.clearNativeBrokerErrorCode(); - return result; - }) - .catch((error: AuthError) => { - nativeATMeasurement.end({ - success: false, - errorCode: error.errorCode, - subErrorCode: error.subError, - isNativeBroker: true, - }); - throw error; + }) + .catch((error: AuthError) => { + nativeATMeasurement.end({ + success: false, + errorCode: error.errorCode, + subErrorCode: error.subError, + isNativeBroker: true, }); - } catch (e) { - if (e instanceof NativeAuthError) { - serverTelemetryManager.setNativeBrokerErrorCode( - e.errorCode - ); - } - throw e; - } - } else if ( - this.platformAuthType === PLATFORM_DOM_PROVIDER && - this.platformAuthProvider instanceof PlatformDOMHandler - ) { - try { - const nativeRequest = await this.initializeNativeDOMRequest( - request - ); - const response = await ( - this.platformAuthProvider as PlatformDOMHandler - ).sendMessage(nativeRequest); - return await this.handleNativeDOMResponse( - nativeRequest, - response, - reqTimestamp - ); - } catch (e) { - if (e instanceof NativeAuthError) { - serverTelemetryManager.setNativeBrokerErrorCode( - e.errorCode - ); - } - throw e; + throw error; + }); + } catch (e) { + if (e instanceof NativeAuthError) { + serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode); } - } else { - throw "Platform broker unavailable or unrecognized"; + throw e; } } @@ -313,7 +257,7 @@ export class NativeInteractionClient extends BaseInteractionClient { * @returns CommonSilentFlowRequest */ private createSilentCacheRequest( - request: NativeExtensionTokenRequest, + request: PlatformBrokerRequest, cachedAccount: AccountInfo ): CommonSilentFlowRequest { return { @@ -333,7 +277,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ protected async acquireTokensFromCache( nativeAccountId: string, - request: NativeExtensionTokenRequest + request: PlatformBrokerRequest ): Promise { if (!nativeAccountId) { this.logger.warning( @@ -395,16 +339,8 @@ export class NativeInteractionClient extends BaseInteractionClient { remainingParameters ); - const messageBody: NativeExtensionRequestBody = { - method: NativeExtensionMethod.GetToken, - request: nativeRequest, - }; - try { - const response: object = await ( - this.platformAuthProvider as NativeMessageHandler - ).sendMessage(messageBody); - this.validateNativeResponse(response); + await this.platformAuthProvider.sendMessage(nativeRequest); } catch (e) { // Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise if (e instanceof NativeAuthError) { @@ -484,31 +420,24 @@ export class NativeInteractionClient extends BaseInteractionClient { ) ); - const messageBody: NativeExtensionRequestBody = { - method: NativeExtensionMethod.GetToken, - request: request, - }; - const reqTimestamp = TimeUtils.nowSeconds(); try { this.logger.verbose( "NativeInteractionClient - handleRedirectPromise sending message to native broker." ); - const response: object = await ( - this.platformAuthProvider as NativeMessageHandler - ).sendMessage(messageBody); - this.validateNativeResponse(response); - const result = this.handleNativeResponse( - response as NativeResponse, + const response: PlatformBrokerResponse = + await this.platformAuthProvider.sendMessage(request); + const authResult = await this.handleNativeResponse( + response, request, reqTimestamp ); - const res = await result; + const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId); serverTelemetryManager.clearNativeBrokerErrorCode(); - return res; + return authResult; } catch (e) { throw e; } @@ -530,8 +459,8 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param reqTimestamp */ protected async handleNativeResponse( - response: NativeResponse, - request: NativeExtensionTokenRequest, + response: PlatformBrokerResponse, + request: PlatformBrokerRequest, reqTimestamp: number ): Promise { this.logger.trace( @@ -617,98 +546,6 @@ export class NativeInteractionClient extends BaseInteractionClient { return result; } - protected async handleNativeDOMResponse( - request: PlatformDOMTokenRequest, - response: PlatformDOMTokenResponse, - reqTimestamp: number - ): Promise { - this.logger.trace("PlatformDOMHandler: handleNativeDOMResponse called"); - // eslint-disable-next-line no-console - console.log(response); - // generate identifiers - - const idTokenClaims = AuthToken.extractTokenClaims( - response.idToken ?? Constants.EMPTY_STRING, - base64Decode - ); - // Save account in browser storage - const homeAccountIdentifier = AccountEntity.generateHomeAccountId( - response.clientInfo || Constants.EMPTY_STRING, - AuthorityType.Default, - this.logger, - this.browserCrypto, - idTokenClaims - ); - - const cachedhomeAccountId = - this.browserStorage.getAccountInfoFilteredBy({ - nativeAccountId: request.accountId, - })?.homeAccountId; - - // add exception for double brokering, please note this is temporary and will be fortified in future - if ( - request.extraParameters?.child_client_id && - response.account?.id !== request.accountId - ) { - this.logger.info( - "handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch" - ); - } else if ( - homeAccountIdentifier !== cachedhomeAccountId && - response.account?.id !== request.accountId - ) { - // User switch in native broker prompt is not supported. All users must first sign in through web flow to ensure server state is in sync - throw createNativeAuthError(NativeAuthErrorCodes.userSwitch); - } - - // Get the preferred_cache domain for the given authority - const authority = await this.getDiscoveredAuthority({ - requestAuthority: request.authority, - }); - - const baseAccount = buildAccountToCache( - this.browserStorage, - authority, - homeAccountIdentifier, - base64Decode, - idTokenClaims, - response.clientInfo, - undefined, // environment - idTokenClaims.tid, - undefined, // auth code payload - response.account?.id, - this.logger - ); - - // Ensure expires_in is in number format - response.expiresIn = Number(response.expiresIn); - - // generate authenticationResult - const authenticationResult = - await this.generateAuthenticationResultFromDOMResponse( - response, - request, - idTokenClaims, - baseAccount, - authority.canonicalAuthority, - reqTimestamp - ); - - // cache accounts and tokens in the appropriate storage - await this.cacheAccount(baseAccount); - await this.cacheNativeTokens( - response, - request, - homeAccountIdentifier, - idTokenClaims, - response.accessToken || "", - authenticationResult.tenantId, - reqTimestamp - ); - - return authenticationResult; - } - /** * creates an homeAccountIdentifier for the account * @param response @@ -716,7 +553,7 @@ export class NativeInteractionClient extends BaseInteractionClient { * @returns */ protected createHomeAccountIdentifier( - response: NativeResponse, + response: PlatformBrokerResponse, idTokenClaims: TokenClaims ): string { // Save account in browser storage @@ -749,8 +586,8 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param response */ async generatePopAccessToken( - response: NativeResponse, - request: NativeExtensionTokenRequest + response: PlatformBrokerResponse, + request: PlatformBrokerRequest ): Promise { if ( request.tokenType === AuthenticationScheme.POP && @@ -808,8 +645,8 @@ export class NativeInteractionClient extends BaseInteractionClient { * @returns */ protected async generateAuthenticationResult( - response: NativeResponse, - request: NativeExtensionTokenRequest, + response: PlatformBrokerResponse, + request: PlatformBrokerRequest, idTokenClaims: TokenClaims, accountEntity: AccountEntity, authority: string, @@ -885,91 +722,6 @@ export class NativeInteractionClient extends BaseInteractionClient { return result; } - /** - * Generates authentication result from DOM response - * @param response - * @param request - * @param idTokenObj - * @param accountEntity - * @param authority - * @param reqTimestamp - * @returns - */ - protected async generateAuthenticationResultFromDOMResponse( - response: PlatformDOMTokenResponse, - request: PlatformDOMTokenRequest, - idTokenClaims: TokenClaims, - accountEntity: AccountEntity, - authority: string, - reqTimestamp: number - ): Promise { - // Add Native Broker fields to Telemetry - const mats = this.addTelemetryFromNativeResponse( - response.properties?.MATS - ); - - // If scopes not returned in server response, use request scopes - const responseScopes = this.generateScopes( - request.scope, - response.scopes - ); - - const accountProperties = response.account?.properties || {}; - const uid = - accountProperties["UID"] || - idTokenClaims.oid || - idTokenClaims.sub || - Constants.EMPTY_STRING; - const tid = - accountProperties["TenantId"] || - idTokenClaims.tid || - Constants.EMPTY_STRING; - - const accountInfo: AccountInfo | null = updateAccountTenantProfileData( - accountEntity.getAccountInfo(), - undefined, // tenantProfile optional - idTokenClaims, - response.idToken - ); - - /** - * In pairwise broker flows, this check prevents the broker's native account id - * from being returned over the embedded app's account id. - */ - if (accountInfo.nativeAccountId !== response.account?.id) { - accountInfo.nativeAccountId = response.account?.id; - } - - // Generate PoP token as needed - const responseAccessToken = response.accessToken; - const tokenType = - request.extraParameters?.tokenType === AuthenticationScheme.POP - ? AuthenticationScheme.POP - : AuthenticationScheme.BEARER; - - const result: AuthenticationResult = { - authority: authority, - uniqueId: uid, - tenantId: tid, - scopes: responseScopes.asArray(), - account: accountInfo, - idToken: response.idToken || "", - idTokenClaims: idTokenClaims, - accessToken: responseAccessToken || "", - fromCache: mats ? this.isResponseFromCache(mats) : false, - // Request timestamp and response expiresIn are in seconds, converting to Date for AuthenticationResult - expiresOn: TimeUtils.toDateFromSeconds( - reqTimestamp + (response.expiresIn || 0) - ), - tokenType: tokenType, - correlationId: this.correlationId, - state: response.state, - fromNativeBroker: true, - }; - - return result; - } - /** * cache the account entity in browser storage * @param accountEntity @@ -997,8 +749,8 @@ export class NativeInteractionClient extends BaseInteractionClient { * @param reqTimestamp */ cacheNativeTokens( - response: NativeResponse | PlatformDOMTokenResponse, - request: NativeExtensionTokenRequest | PlatformDOMTokenRequest, + response: PlatformBrokerResponse, + request: PlatformBrokerRequest, homeAccountIdentifier: string, idTokenClaims: TokenClaims, responseAccessToken: string, @@ -1009,28 +761,22 @@ export class NativeInteractionClient extends BaseInteractionClient { CacheHelpers.createIdTokenEntity( homeAccountIdentifier, request.authority, - (response as NativeResponse).id_token || - (response as PlatformDOMTokenResponse).idToken || - "", + response.id_token || "", request.clientId, idTokenClaims.tid || "" ); // cache accessToken in inmemory storage - const expiresIn: number = this.getExpiresInValue( - (request as NativeExtensionTokenRequest).tokenType || - (request as PlatformDOMTokenRequest).extraParameters - ?.tokenType || - "", - (response as NativeResponse).expires_in || - (response as PlatformDOMTokenResponse).expiresIn - ); - + const expiresIn: number = + request.tokenType === AuthenticationScheme.POP + ? Constants.SHR_NONCE_VALIDITY + : (typeof response.expires_in === "string" + ? parseInt(response.expires_in, 10) + : response.expires_in) || 0; const tokenExpirationSeconds = reqTimestamp + expiresIn; const responseScopes = this.generateScopes( - request.scope, - (response as NativeResponse).scope || - (response as PlatformDOMTokenResponse).scopes + response.scope, + request.scope ); const cachedAccessToken: AccessTokenEntity | null = @@ -1045,13 +791,9 @@ export class NativeInteractionClient extends BaseInteractionClient { 0, base64Decode, undefined, - ((request as NativeExtensionTokenRequest) - .tokenType as AuthenticationScheme) || - ((request as PlatformDOMTokenRequest).extraParameters - ?.tokenType as AuthenticationScheme), + request.tokenType as AuthenticationScheme, undefined, - (request as NativeExtensionTokenRequest).keyId || - (request as PlatformDOMTokenRequest).extraParameters?.keyId + request.keyId ); const nativeCacheRecord = { @@ -1111,28 +853,6 @@ export class NativeInteractionClient extends BaseInteractionClient { return mats; } - /** - * Validates native platform response before processing - * @param response - */ - private validateNativeResponse(response: object): NativeResponse { - if ( - response.hasOwnProperty("access_token") && - response.hasOwnProperty("id_token") && - response.hasOwnProperty("client_info") && - response.hasOwnProperty("account") && - response.hasOwnProperty("scope") && - response.hasOwnProperty("expires_in") - ) { - return response as NativeResponse; - } else { - throw createAuthError( - AuthErrorCodes.unexpectedError, - "Response missing expected properties." - ); - } - } - /** * Gets MATS telemetry from native response * @param response @@ -1174,7 +894,7 @@ export class NativeInteractionClient extends BaseInteractionClient { */ protected async initializeNativeRequest( request: PopupRequest | SsoSilentRequest - ): Promise { + ): Promise { this.logger.trace( "NativeInteractionClient - initializeNativeRequest called" ); @@ -1186,7 +906,7 @@ export class NativeInteractionClient extends BaseInteractionClient { const scopeSet = new ScopeSet(scopes || []); scopeSet.appendScopes(OIDC_DEFAULT_SCOPES); - const validatedRequest: NativeExtensionTokenRequest = { + const validatedRequest: PlatformBrokerRequest = { ...remainingProperties, accountId: this.accountId, clientId: this.config.auth.clientId, @@ -1257,118 +977,6 @@ export class NativeInteractionClient extends BaseInteractionClient { return validatedRequest; } - protected async initializeNativeDOMRequest( - request: PopupRequest | SilentRequest | SsoSilentRequest - ): Promise { - this.logger.trace( - "NativeInteractionClient: initializeNativeDOMRequest called" - ); - - const canonicalAuthority = await this.getCanonicalAuthority(request); - - const { - correlationId, - redirectUri, - scopes, - state, - extraQueryParameters, - tokenQueryParameters, - storeInCache, - ...remainingProperties - } = request; - - delete remainingProperties.authority; - - const scopeSet = new ScopeSet(scopes || []); - scopeSet.appendScopes(OIDC_DEFAULT_SCOPES); - - const validExtraParameters = { - ...remainingProperties, - ...extraQueryParameters, - ...tokenQueryParameters, - prompt: this.getPrompt(request.prompt), - tokenType: request.authenticationScheme, - windowTitleSubstring: document.title, - telemetry: NativeConstants.MATS_TELEMETRY, - keyId: request.popKid, - }; - - // Filter and convert validExtraParameters to StringDict - const validExtraParametersDict: StringDict = Object.entries( - validExtraParameters - ).reduce((acc, [key, value]) => { - if (typeof value === "string") { - acc[key] = value; - } - return acc; - }, {} as StringDict); - - const nativeRequest: PlatformDOMTokenRequest = { - accountId: this.accountId, - brokerId: ( - this.platformAuthProvider as PlatformDOMHandler - ).getExtensionId(), - authority: canonicalAuthority.urlString, - clientId: this.config.auth.clientId || "", - correlationId: correlationId || this.correlationId, - extraParameters: validExtraParametersDict, - isSecurityTokenService: true, - redirectUri: this.getRedirectUri(redirectUri), - scope: scopeSet.printScopes(), - state: state, - storeInCache: storeInCache, - }; - - nativeRequest.extraParameters = nativeRequest.extraParameters || {}; - this.handleExtraBrokerParams(nativeRequest); - - // Check for PoP token requests: signPopToken should only be set to true if popKid is not set - if (nativeRequest.extraParameters.signPopToken && !!request.popKid) { - throw createBrowserAuthError( - BrowserAuthErrorCodes.invalidPopTokenRequest - ); - } - - if (request.authenticationScheme === AuthenticationScheme.POP) { - // add POP request type - const shrParameters: SignedHttpRequestParameters = { - resourceRequestUri: request.resourceRequestUri, - resourceRequestMethod: request.resourceRequestMethod, - shrClaims: request.shrClaims, - shrNonce: request.shrNonce, - }; - - const popTokenGenerator = new PopTokenGenerator(this.browserCrypto); - - // generate reqCnf if not provided in the request - let reqCnfData; - if (!nativeRequest.extraParameters?.keyId) { - const generatedReqCnfData = await invokeAsync( - popTokenGenerator.generateCnf.bind(popTokenGenerator), - PerformanceEvents.PopTokenGenerateCnf, - this.logger, - this.performanceClient, - request.correlationId - )(shrParameters, this.logger); - reqCnfData = generatedReqCnfData.reqCnfString; - nativeRequest.extraParameters.keyId = generatedReqCnfData.kid; - nativeRequest.extraParameters.signPopToken = "true"; - } else { - reqCnfData = this.browserCrypto.base64UrlEncode( - JSON.stringify({ - kid: nativeRequest.extraParameters?.keyId, - }) - ); - nativeRequest.extraParameters.signPopToken = "false"; - } - - // SPAs require whole string to be passed to broker - nativeRequest.extraParameters.reqCnf = reqCnfData; - } - this.addRequestSKUs(nativeRequest); - return nativeRequest; - } - private async getCanonicalAuthority( request: PopupRequest | SsoSilentRequest ): Promise { @@ -1431,11 +1039,11 @@ export class NativeInteractionClient extends BaseInteractionClient { /** * Handles extra broker request parameters - * @param request {NativeExtensionTokenRequest} + * @param request {PlatformBrokerRequest} * @private */ private handleExtraBrokerParams( - request: NativeExtensionTokenRequest | PlatformDOMTokenRequest + request: PlatformBrokerRequest | PlatformDOMTokenRequest ): void { const hasExtraBrokerParams = request.extraParameters && diff --git a/lib/msal-browser/src/interaction_client/PopupClient.ts b/lib/msal-browser/src/interaction_client/PopupClient.ts index 05fb89dbcc..5effc528f9 100644 --- a/lib/msal-browser/src/interaction_client/PopupClient.ts +++ b/lib/msal-browser/src/interaction_client/PopupClient.ts @@ -47,7 +47,7 @@ import * as ResponseHandler from "../response/ResponseHandler.js"; import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; -import { PlatformAuthProvider } from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; export type PopupParams = { @@ -226,7 +226,7 @@ export class PopupClient extends StandardInteractionClient { BrowserUtils.preconnect(validRequest.authority); } - const isPlatformBroker = PlatformAuthProvider.isBrokerAvailable( + const isPlatformBroker = isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, diff --git a/lib/msal-browser/src/interaction_client/RedirectClient.ts b/lib/msal-browser/src/interaction_client/RedirectClient.ts index 5583c793c8..4740869c05 100644 --- a/lib/msal-browser/src/interaction_client/RedirectClient.ts +++ b/lib/msal-browser/src/interaction_client/RedirectClient.ts @@ -48,7 +48,7 @@ import * as ResponseHandler from "../response/ResponseHandler.js"; import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; -import { PlatformAuthProvider } from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; function getNavigationType(): NavigationTimingType | undefined { @@ -111,7 +111,7 @@ export class RedirectClient extends StandardInteractionClient { this.correlationId )(request, InteractionType.Redirect); - validRequest.platformBroker = PlatformAuthProvider.isBrokerAvailable( + validRequest.platformBroker = isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, diff --git a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts index 48e45cfc71..0a19468681 100644 --- a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts @@ -43,7 +43,7 @@ import * as ResponseHandler from "../response/ResponseHandler.js"; import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; -import { PlatformAuthProvider } from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; export class SilentIframeClient extends StandardInteractionClient { @@ -126,7 +126,7 @@ export class SilentIframeClient extends StandardInteractionClient { this.performanceClient, request.correlationId )(inputRequest, InteractionType.Silent); - silentRequest.platformBroker = PlatformAuthProvider.isBrokerAvailable( + silentRequest.platformBroker = isBrokerAvailable( this.config, this.logger, this.platformAuthProvider, diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 9d20d12790..f2f63440d3 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -97,7 +97,7 @@ import { SilentAuthCodeClient } from "../../src/interaction_client/SilentAuthCod import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; -import { NativeExtensionTokenRequest } from "../../src/broker/nativeBroker/NativeRequest.js"; +import { PlatformBrokerRequest } from "../../src/broker/nativeBroker/NativeRequest.js"; import { NativeAuthError } from "../../src/error/NativeAuthError.js"; import { StandardController } from "../../src/controllers/StandardController.js"; import { AuthenticationResult } from "../../src/response/AuthenticationResult.js"; @@ -771,7 +771,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { "isInteractionInProgress" ).mockReturnValue(true); - const nativeRequest: NativeExtensionTokenRequest = { + const nativeRequest: PlatformBrokerRequest = { authority: TEST_CONFIG.validAuthority, clientId: TEST_CONFIG.MSAL_CLIENT_ID, scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "), @@ -890,7 +890,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { "getCachedRequest" ).mockReturnValue([testRequest, TEST_CONFIG.TEST_VERIFIER]); - const nativeRequest: NativeExtensionTokenRequest = { + const nativeRequest: PlatformBrokerRequest = { authority: TEST_CONFIG.validAuthority, clientId: TEST_CONFIG.MSAL_CLIENT_ID, scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "), diff --git a/lib/msal-browser/test/utils/StringConstants.ts b/lib/msal-browser/test/utils/StringConstants.ts index b209fbd0a1..76d8fdf7cb 100644 --- a/lib/msal-browser/test/utils/StringConstants.ts +++ b/lib/msal-browser/test/utils/StringConstants.ts @@ -16,6 +16,7 @@ import { version } from "../../src/packageMetadata.js"; import { base64Decode, base64DecToArr } from "../../src/encode/Base64Decode.js"; import { urlEncodeArr } from "../../src/encode/Base64Encode.js"; import { AuthenticationResult } from "../../src/response/AuthenticationResult.js"; +import { PlatformDOMTokenResponse } from "../../src/broker/nativeBroker/NativeResponse.js"; /** * This file contains the string constants used by the test classes. @@ -579,3 +580,47 @@ export function getTestAuthenticationResult(): AuthenticationResult { familyId: "", }; } + +export const PlatformDOMTestTokenResponseObject = { + isSuccess: true, + state: "1234state", + accessToken: "eyJ0eXAiOiJKV1QiLCJub25j…", + expiresIn: 1744768881, + account: { + userName: "idlab@msidlab4.onmicrosoft.com", + id: "test-nativeAccountId", + properties: {}, + }, + clientInfo: + "clienteyJ1aWQiOiJkMTdkMzcwNi0xZTRlLTQ2OTUtODA0OC1lZjYxOTZlOTZm", + idToken: TEST_TOKENS.IDTOKEN_V2, + scopes: "openid profile User.Read email", + proofOfPossessionPayload: "successshr", + extendedLifetimeToken: true, + properties: {}, + error: { + code: "", + description: "", + errorCode: "", + properties: {}, + status: "", + protocolError: "", + }, +}; + +export const PlatformDOMTestErrorResponseObject = { + isSuccess: false, + expiresIn: 0, + extendedLifetimeToken: false, + error: { + code: "OSError", + description: + 'Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=-6000 "(null)" UserInfo={NSUnderlyingError=0x1319056b0 {Error Domain=MSALErrorDomain Code=-50000 "(null)" UserInfo={MSALErrorDescriptionKey=redirectUri host doesn\'t match sender host., MSALBrokerVersionKey=1.0, MSALInternalErrorCodeKey=-42008, MSALBrowserNativeMessageErrorStatus=PERSISTENT_ERROR}}}', + errorCode: "-6000", + properties: { + MATS: '{"x_ms_clitelem":"1,0,0,,I","ui_visible":true}', + }, + status: "PERSISTENT_ERROR", + protocolError: "", + }, +}; From 074e61893759118ac7568bcb1f053c6d185e0de6 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Thu, 1 May 2025 14:22:23 -0700 Subject: [PATCH 11/30] added IPlatformBrokerHandler interface --- .../src/app/PublicClientApplication.ts | 16 ++++---- .../nativeBroker/IPlatformBrokerHandler.ts | 19 +++++++++ .../nativeBroker/NativeMessageHandler.ts | 7 +++- .../nativeBroker/PlatformAuthProvider.ts | 7 +--- .../broker/nativeBroker/PlatformDOMHandler.ts | 17 ++++---- .../src/controllers/StandardController.ts | 39 ++++--------------- .../BaseInteractionClient.ts | 13 ++----- .../NativeInteractionClient.ts | 9 ++--- .../src/interaction_client/PopupClient.ts | 12 ++---- .../src/interaction_client/RedirectClient.ts | 10 ++--- .../SilentAuthCodeClient.ts | 7 +--- .../interaction_client/SilentIframeClient.ts | 13 ++----- lib/msal-browser/src/protocol/Authorize.ts | 21 ++++------ .../src/utils/BrowserConstants.ts | 2 + 14 files changed, 78 insertions(+), 114 deletions(-) create mode 100644 lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts diff --git a/lib/msal-browser/src/app/PublicClientApplication.ts b/lib/msal-browser/src/app/PublicClientApplication.ts index 65e5a9e64d..98205a27b2 100644 --- a/lib/msal-browser/src/app/PublicClientApplication.ts +++ b/lib/msal-browser/src/app/PublicClientApplication.ts @@ -51,14 +51,14 @@ export class PublicClientApplication implements IPublicClientApplication { */ public static async createPublicClientApplication( configuration: Configuration, - featureSupportConfiguration?: FeatureSupportConfiguration + featureConfig?: FeatureSupportConfiguration ): Promise { const controller = await ControllerFactory.createV3Controller( configuration ); const pca = new PublicClientApplication( configuration, - featureSupportConfiguration, + featureConfig, controller ); @@ -85,20 +85,18 @@ export class PublicClientApplication implements IPublicClientApplication { * Full B2C functionality will be available in this library in future versions. * * @param configuration Object for the MSAL PublicClientApplication instance + * @param featureConfig Optional parameter to explictly enable any feature support. * @param IController Optional parameter to explictly set the controller. (Will be removed when we remove public constructor) */ public constructor( configuration: Configuration, - featureSupportConfiguration?: FeatureSupportConfiguration, + featureConfig?: FeatureSupportConfiguration, controller?: IController ) { this.controller = controller || new StandardController( - new StandardOperatingContext( - configuration, - featureSupportConfiguration - ) + new StandardOperatingContext(configuration, featureConfig) ); } @@ -455,7 +453,7 @@ export class PublicClientApplication implements IPublicClientApplication { */ export async function createNestablePublicClientApplication( configuration: Configuration, - featureSupportConfiguration?: FeatureSupportConfiguration + featureConfig?: FeatureSupportConfiguration ): Promise { const nestedAppAuth = new NestedAppOperatingContext(configuration); await nestedAppAuth.initialize(); @@ -464,7 +462,7 @@ export async function createNestablePublicClientApplication( const controller = new NestedAppAuthController(nestedAppAuth); const nestablePCA = new PublicClientApplication( configuration, - featureSupportConfiguration, + featureConfig, controller ); await nestablePCA.initialize(); diff --git a/lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts b/lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts new file mode 100644 index 0000000000..4a297e2052 --- /dev/null +++ b/lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { PlatformBrokerRequest } from "./NativeRequest.js"; +import { PlatformBrokerResponse } from "./NativeResponse.js"; + +/** + * Interface for the Platform Broker Handlers + */ +export interface IPlatformBrokerHandler { + getExtensionId(): string | undefined; + getExtensionVersion(): string | undefined; + sendMessage( + request: PlatformBrokerRequest + ): Promise; + validateNativeResponse(response: object): PlatformBrokerResponse; +} diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts index 8a77a59473..b3bc0779b2 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts @@ -28,6 +28,7 @@ import { } from "../../error/BrowserAuthError.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; import { PlatformBrokerResponse } from "./NativeResponse.js"; +import { IPlatformBrokerHandler } from "./IPlatformBrokerHandler.js"; type ResponseResolvers = { resolve: (value: T | PromiseLike) => void; @@ -36,7 +37,7 @@ type ResponseResolvers = { ) => void; }; -export class NativeMessageHandler { +export class NativeMessageHandler implements IPlatformBrokerHandler { private extensionId: string | undefined; private extensionVersion: string | undefined; private logger: Logger; @@ -48,6 +49,7 @@ export class NativeMessageHandler { private readonly windowListener: (event: MessageEvent) => void; private readonly performanceClient: IPerformanceClient; private readonly handshakeEvent: InProgressPerformanceEvent; + platformAuthType: string; constructor( logger: Logger, @@ -66,6 +68,7 @@ export class NativeMessageHandler { this.handshakeEvent = performanceClient.startMeasurement( PerformanceEvents.NativeMessageHandlerHandshake ); + this.platformAuthType = NativeConstants.PLATFORM_EXTENSION_PROVIDER; } /** @@ -369,7 +372,7 @@ export class NativeMessageHandler { * Validates native platform response before processing * @param response */ - private validateNativeResponse(response: object): PlatformBrokerResponse { + validateNativeResponse(response: object): PlatformBrokerResponse { if ( response.hasOwnProperty("access_token") && response.hasOwnProperty("id_token") && diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 56580f9671..d6b863edbc 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -17,10 +17,7 @@ import { import { BrowserPerformanceClient } from "../../telemetry/BrowserPerformanceClient.js"; import { NativeMessageHandler } from "./NativeMessageHandler.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; -import { PlatformDOMHandler } from "./PlatformDOMHandler.js"; - -export const PLATFORM_EXTENSION_PROVIDER = "NativeMessageHandler"; -export const PLATFORM_DOM_PROVIDER = "PlatformDOMHandler"; +import { IPlatformBrokerHandler } from "./IPlatformBrokerHandler.js"; /** * Checks if the platform broker is available in the current environment. @@ -99,7 +96,7 @@ export async function isPlatformBrokerAvailable( export function isBrokerAvailable( config: BrowserConfiguration, logger: Logger, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, + platformAuthProvider?: IPlatformBrokerHandler, authenticationScheme?: AuthenticationScheme ): boolean { logger.trace("isBrokerAvailable called"); diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts index 535722cf8b..b93c6d41c7 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts @@ -21,13 +21,15 @@ import { PlatformDOMTokenResponse, } from "./NativeResponse.js"; import { createNativeAuthError } from "../../error/NativeAuthError.js"; +import { IPlatformBrokerHandler } from "./IPlatformBrokerHandler.js"; -export class PlatformDOMHandler { +export class PlatformDOMHandler implements IPlatformBrokerHandler { protected logger: Logger; protected performanceClient: IPerformanceClient; protected correlationId: string; protected brokerId: string; protected extensionVersion: string; + platformAuthType: string; constructor( logger: Logger, @@ -40,6 +42,7 @@ export class PlatformDOMHandler { this.brokerId = brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID; this.correlationId = correlationId || createNewGuid(); this.extensionVersion = ""; + this.platformAuthType = NativeConstants.PLATFORM_DOM_PROVIDER; } /** @@ -87,9 +90,7 @@ export class PlatformDOMHandler { await window.navigator.platformAuthentication.executeGetToken( platformDOMRequest ); - const validatedResponse: PlatformDOMTokenResponse = - this.validateNativeResponse(response); - return this.convertToNativeResponse(validatedResponse); + return this.validateNativeResponse(response); } catch (e) { this.logger.error( "PlatformDOMHandler: executeGetToken DOM API error" @@ -140,7 +141,7 @@ export class PlatformDOMHandler { return platformDOMRequest; } - private validateNativeResponse(response: object): PlatformDOMTokenResponse { + validateNativeResponse(response: object): PlatformBrokerResponse { if (response.hasOwnProperty("isSuccess")) { if ( response.hasOwnProperty("access_token") && @@ -153,7 +154,9 @@ export class PlatformDOMHandler { this.logger.trace( "PlatformDOMHandler: platform broker returned successful and valid response" ); - return response as PlatformDOMTokenResponse; + return this.convertToPlatformBrokerResponse( + response as PlatformDOMTokenResponse + ); } else if (response.hasOwnProperty("error")) { const errorResponse = response as PlatformDOMTokenResponse; if (errorResponse.isSuccess === false) { @@ -179,7 +182,7 @@ export class PlatformDOMHandler { ); } - private convertToNativeResponse( + private convertToPlatformBrokerResponse( response: PlatformDOMTokenResponse ): PlatformBrokerResponse { this.logger.trace("PlatformDOMHandler: convertToNativeResponse called"); diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index c53412506d..48381b5b43 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -89,12 +89,9 @@ import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; -import { - isBrokerAvailable, - PLATFORM_DOM_PROVIDER, - PLATFORM_EXTENSION_PROVIDER, -} from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; function getAccountType( account?: AccountInfo @@ -167,12 +164,7 @@ export class StandardController implements IController { >; // Native Extension Provider - protected platformAuthProvider: - | NativeMessageHandler - | PlatformDOMHandler - | undefined; - - private platformAuthType: string; + protected platformAuthProvider: IPlatformBrokerHandler | undefined; // Hybrid auth code responses private hybridAuthCodeResponses: Map>; @@ -304,8 +296,6 @@ export class StandardController implements IController { // Register listener functions this.trackPageVisibilityWithMeasurement = this.trackPageVisibilityWithMeasurement.bind(this); - - this.platformAuthType = Constants.EMPTY_STRING; } static async createController( @@ -368,7 +358,7 @@ export class StandardController implements IController { if (allowPlatformBroker) { try { // check if platform authentication is available via DOM or browser extension and create relevant handlers - await this.getPlatformAuthProvider(); + await this.setPlatformAuthProvider(); } catch (e) { this.logger.verbose(e as string); } @@ -400,7 +390,7 @@ export class StandardController implements IController { }); } - protected async getPlatformAuthProvider( + protected async setPlatformAuthProvider( correlationId?: string ): Promise { this.logger.trace("getPlatformAuthProvider called", correlationId); @@ -411,7 +401,6 @@ export class StandardController implements IController { if (domPlatformApiSupported) { this.platformAuthProvider = domPlatformApiSupported; - this.platformAuthType = PLATFORM_DOM_PROVIDER; } else { this.platformAuthProvider = await NativeMessageHandler.createProvider( @@ -419,7 +408,6 @@ export class StandardController implements IController { this.config.system.nativeBrokerHandshakeTimeout, this.performanceClient ); - this.platformAuthType = PLATFORM_EXTENSION_PROVIDER; this.logger.trace( "Platform API available via browser extension", @@ -577,7 +565,6 @@ export class StandardController implements IController { ApiId.handleRedirectPromise, this.performanceClient, this.platformAuthProvider, - this.platformAuthType, platformBrokerRequest.accountId, this.nativeInternalStorage, platformBrokerRequest.correlationId @@ -794,7 +781,6 @@ export class StandardController implements IController { ApiId.acquireTokenRedirect, this.performanceClient, this.platformAuthProvider, - this.platformAuthType, this.getNativeAccountId(request), this.nativeInternalStorage, correlationId @@ -807,7 +793,6 @@ export class StandardController implements IController { isFatalNativeAuthError(e) ) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt - this.platformAuthType = Constants.EMPTY_STRING; const redirectClient = this.createRedirectClient(correlationId); return redirectClient.acquireToken(request); @@ -925,7 +910,6 @@ export class StandardController implements IController { isFatalNativeAuthError(e) ) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt - this.platformAuthType = Constants.EMPTY_STRING; const popupClient = this.createPopupClient(correlationId); return popupClient.acquireToken(request, pkce); @@ -1085,7 +1069,6 @@ export class StandardController implements IController { // If native token acquisition fails for availability reasons fallback to standard flow if (e instanceof NativeAuthError && isFatalNativeAuthError(e)) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt - this.platformAuthType = Constants.EMPTY_STRING; const silentIframeClient = this.createSilentIframeClient( validRequest.correlationId ); @@ -1243,7 +1226,6 @@ export class StandardController implements IController { isFatalNativeAuthError(e) ) { this.platformAuthProvider = undefined; // If extension gets uninstalled during session prevent future requests from continuing to attempt - this.platformAuthType = Constants.EMPTY_STRING; } throw e; }); @@ -1653,7 +1635,7 @@ export class StandardController implements IController { cacheLookupPolicy?: CacheLookupPolicy ): Promise { this.logger.trace("acquireTokenNative called"); - if (!this.platformAuthType || !this.platformAuthProvider) { + if (!this.platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); @@ -1669,7 +1651,6 @@ export class StandardController implements IController { apiId, this.performanceClient, this.platformAuthProvider, - this.platformAuthType, accountId || this.getNativeAccountId(request), this.nativeInternalStorage, request.correlationId @@ -1687,7 +1668,7 @@ export class StandardController implements IController { accountId?: string ): boolean { this.logger.trace("canUsePlatformBroker called"); - if (!this.platformAuthType) { + if (!this.platformAuthProvider) { this.logger.trace( "canUsePlatformBroker: platform broker unavilable, returning false" ); @@ -1769,7 +1750,6 @@ export class StandardController implements IController { this.performanceClient, this.nativeInternalStorage, this.platformAuthProvider, - this.platformAuthType, correlationId ); } @@ -1789,7 +1769,6 @@ export class StandardController implements IController { this.performanceClient, this.nativeInternalStorage, this.platformAuthProvider, - this.platformAuthType, correlationId ); } @@ -1812,7 +1791,6 @@ export class StandardController implements IController { this.performanceClient, this.nativeInternalStorage, this.platformAuthProvider, - this.platformAuthType, correlationId ); } @@ -1832,7 +1810,6 @@ export class StandardController implements IController { this.navigationClient, this.performanceClient, this.platformAuthProvider, - this.platformAuthType, correlationId ); } @@ -1872,7 +1849,6 @@ export class StandardController implements IController { ApiId.acquireTokenByCode, this.performanceClient, this.platformAuthProvider, - this.platformAuthType, correlationId ); } @@ -2407,7 +2383,6 @@ export class StandardController implements IController { "acquireTokenSilent - native platform unavailable, falling back to web flow" ); this.platformAuthProvider = undefined; // Prevent future requests from continuing to attempt - this.platformAuthType = Constants.EMPTY_STRING; // Cache will not contain tokens, given that previous WAM requests succeeded. Skip cache and RT renewal and go straight to iframe renewal throw createClientAuthError( ClientAuthErrorCodes.tokenRefreshRequired diff --git a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts index a82a2695a4..615961952f 100644 --- a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts @@ -34,11 +34,10 @@ 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 { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { ClearCacheRequest } from "../request/ClearCacheRequest.js"; import { createNewGuid } from "../crypto/BrowserCrypto.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; export abstract class BaseInteractionClient { protected config: BrowserConfiguration; @@ -48,11 +47,7 @@ export abstract class BaseInteractionClient { protected logger: Logger; protected eventHandler: EventHandler; protected navigationClient: INavigationClient; - protected platformAuthProvider: - | NativeMessageHandler - | PlatformDOMHandler - | undefined; - protected readonly platformAuthType: string | undefined; + protected platformAuthProvider: IPlatformBrokerHandler | undefined; protected correlationId: string; protected performanceClient: IPerformanceClient; @@ -64,8 +59,7 @@ export abstract class BaseInteractionClient { eventHandler: EventHandler, navigationClient: INavigationClient, performanceClient: IPerformanceClient, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string, + platformAuthProvider?: IPlatformBrokerHandler, correlationId?: string ) { this.config = config; @@ -75,7 +69,6 @@ export abstract class BaseInteractionClient { this.eventHandler = eventHandler; this.navigationClient = navigationClient; this.platformAuthProvider = platformAuthProvider; - this.platformAuthType = platformAuthType; this.correlationId = correlationId || createNewGuid(); this.logger = logger.clone( BrowserConstants.MSAL_SKU, diff --git a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts index 92e1c1a10a..dcd01fbb51 100644 --- a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts @@ -43,7 +43,6 @@ import { EventHandler } from "../event/EventHandler.js"; import { PopupRequest } from "../request/PopupRequest.js"; import { SilentRequest } from "../request/SilentRequest.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { ApiId, TemporaryCacheKeys, @@ -76,12 +75,12 @@ import { SilentCacheClient } from "./SilentCacheClient.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { base64Decode } from "../encode/Base64Decode.js"; import { version } from "../packageMetadata.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; export class NativeInteractionClient extends BaseInteractionClient { protected apiId: ApiId; protected accountId: string; - protected platformAuthProvider: NativeMessageHandler | PlatformDOMHandler; + protected platformAuthProvider: IPlatformBrokerHandler; protected silentCacheClient: SilentCacheClient; protected nativeStorageManager: BrowserCacheManager; protected skus: string; @@ -95,8 +94,7 @@ export class NativeInteractionClient extends BaseInteractionClient { navigationClient: INavigationClient, apiId: ApiId, performanceClient: IPerformanceClient, - provider: NativeMessageHandler | PlatformDOMHandler, - platformAuthType: string, + provider: IPlatformBrokerHandler, accountId: string, nativeStorageImpl: BrowserCacheManager, correlationId?: string @@ -110,7 +108,6 @@ export class NativeInteractionClient extends BaseInteractionClient { navigationClient, performanceClient, provider, - platformAuthType, correlationId ); this.apiId = apiId; diff --git a/lib/msal-browser/src/interaction_client/PopupClient.ts b/lib/msal-browser/src/interaction_client/PopupClient.ts index 5effc528f9..03afbed582 100644 --- a/lib/msal-browser/src/interaction_client/PopupClient.ts +++ b/lib/msal-browser/src/interaction_client/PopupClient.ts @@ -46,9 +46,9 @@ import { AuthenticationResult } from "../response/AuthenticationResult.js"; import * as ResponseHandler from "../response/ResponseHandler.js"; import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; export type PopupParams = { popup?: Window | null; @@ -70,8 +70,7 @@ export class PopupClient extends StandardInteractionClient { navigationClient: INavigationClient, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - platformAuthHandler?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string, + platformAuthHandler?: IPlatformBrokerHandler, correlationId?: string ) { super( @@ -83,7 +82,6 @@ export class PopupClient extends StandardInteractionClient { navigationClient, performanceClient, platformAuthHandler, - platformAuthType, correlationId ); // Properly sets this reference for the unload event. @@ -352,8 +350,7 @@ export class PopupClient extends StandardInteractionClient { this.eventHandler, this.logger, this.performanceClient, - this.platformAuthProvider, - this.platformAuthType + this.platformAuthProvider ); } catch (e) { // Close the synchronous popup if an error is thrown before the window unload event is registered @@ -452,8 +449,7 @@ export class PopupClient extends StandardInteractionClient { this.eventHandler, this.logger, this.performanceClient, - this.platformAuthProvider, - this.platformAuthType + this.platformAuthProvider ); } diff --git a/lib/msal-browser/src/interaction_client/RedirectClient.ts b/lib/msal-browser/src/interaction_client/RedirectClient.ts index 4740869c05..bda721945e 100644 --- a/lib/msal-browser/src/interaction_client/RedirectClient.ts +++ b/lib/msal-browser/src/interaction_client/RedirectClient.ts @@ -37,7 +37,6 @@ import { BrowserAuthErrorCodes, } from "../error/BrowserAuthError.js"; import { RedirectRequest } from "../request/RedirectRequest.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { BrowserConfiguration } from "../config/Configuration.js"; import { BrowserCacheManager } from "../cache/BrowserCacheManager.js"; import { EventHandler } from "../event/EventHandler.js"; @@ -47,9 +46,9 @@ import { AuthenticationResult } from "../response/AuthenticationResult.js"; import * as ResponseHandler from "../response/ResponseHandler.js"; import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; function getNavigationType(): NavigationTimingType | undefined { if ( @@ -79,8 +78,7 @@ export class RedirectClient extends StandardInteractionClient { navigationClient: INavigationClient, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - platformAuthHandler?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string, + platformAuthHandler?: IPlatformBrokerHandler, correlationId?: string ) { super( @@ -92,7 +90,6 @@ export class RedirectClient extends StandardInteractionClient { navigationClient, performanceClient, platformAuthHandler, - platformAuthType, correlationId ); this.nativeStorage = nativeStorageImpl; @@ -586,8 +583,7 @@ export class RedirectClient extends StandardInteractionClient { this.eventHandler, this.logger, this.performanceClient, - this.platformAuthProvider, - this.platformAuthType + this.platformAuthProvider ); } diff --git a/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts b/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts index 5b4fb7305d..212a4ff725 100644 --- a/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts @@ -25,10 +25,9 @@ import { import { InteractionType, ApiId } from "../utils/BrowserConstants.js"; import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js"; import { HybridSpaAuthorizationCodeClient } from "./HybridSpaAuthorizationCodeClient.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { InteractionHandler } from "../interaction_handler/InteractionHandler.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; export class SilentAuthCodeClient extends StandardInteractionClient { private apiId: ApiId; @@ -42,8 +41,7 @@ export class SilentAuthCodeClient extends StandardInteractionClient { navigationClient: INavigationClient, apiId: ApiId, performanceClient: IPerformanceClient, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string, + platformAuthProvider?: IPlatformBrokerHandler, correlationId?: string ) { super( @@ -55,7 +53,6 @@ export class SilentAuthCodeClient extends StandardInteractionClient { navigationClient, performanceClient, platformAuthProvider, - platformAuthType, correlationId ); this.apiId = apiId; diff --git a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts index 0a19468681..3c452c4f3c 100644 --- a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts @@ -36,15 +36,14 @@ import { monitorIframeForHash, } from "../interaction_handler/SilentHandler.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import * as BrowserUtils from "../utils/BrowserUtils.js"; import * as ResponseHandler from "../response/ResponseHandler.js"; import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; export class SilentIframeClient extends StandardInteractionClient { protected apiId: ApiId; @@ -60,8 +59,7 @@ export class SilentIframeClient extends StandardInteractionClient { apiId: ApiId, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string, + platformAuthProvider?: IPlatformBrokerHandler, correlationId?: string ) { super( @@ -73,7 +71,6 @@ export class SilentIframeClient extends StandardInteractionClient { navigationClient, performanceClient, platformAuthProvider, - platformAuthType, correlationId ); this.apiId = apiId; @@ -297,8 +294,7 @@ export class SilentIframeClient extends StandardInteractionClient { this.eventHandler, this.logger, this.performanceClient, - this.platformAuthProvider, - this.platformAuthType + this.platformAuthProvider ); } @@ -414,8 +410,7 @@ export class SilentIframeClient extends StandardInteractionClient { this.eventHandler, this.logger, this.performanceClient, - this.platformAuthProvider, - this.platformAuthType + this.platformAuthProvider ); } } diff --git a/lib/msal-browser/src/protocol/Authorize.ts b/lib/msal-browser/src/protocol/Authorize.ts index 7fd660c2fe..808ca374e4 100644 --- a/lib/msal-browser/src/protocol/Authorize.ts +++ b/lib/msal-browser/src/protocol/Authorize.ts @@ -41,10 +41,9 @@ import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { InteractionHandler } from "../interaction_handler/InteractionHandler.js"; import { BrowserCacheManager } from "../cache/BrowserCacheManager.js"; import { NativeInteractionClient } from "../interaction_client/NativeInteractionClient.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { EventHandler } from "../event/EventHandler.js"; import { decryptEarResponse } from "../crypto/BrowserCrypto.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; /** * Returns map of parameters that are applicable to all calls to /authorize whether using PKCE or EAR @@ -264,12 +263,11 @@ export async function handleResponsePlatformBroker( eventHandler: EventHandler, logger: Logger, performanceClient: IPerformanceClient, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string + platformAuthProvider?: IPlatformBrokerHandler ): Promise { logger.verbose("Account id found, calling WAM for token"); - if (!platformAuthType || !platformAuthProvider) { + if (!platformAuthProvider) { throw createBrowserAuthError( BrowserAuthErrorCodes.nativeConnectionNotEstablished ); @@ -285,7 +283,6 @@ export async function handleResponsePlatformBroker( apiId, performanceClient, platformAuthProvider, - platformAuthType, accountId, nativeStorage, request.correlationId @@ -330,8 +327,7 @@ export async function handleResponseCode( eventHandler: EventHandler, logger: Logger, performanceClient: IPerformanceClient, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string + platformAuthProvider?: IPlatformBrokerHandler ): Promise { // Remove throttle if it exists ThrottlingUtils.removeThrottle( @@ -356,8 +352,7 @@ export async function handleResponseCode( eventHandler, logger, performanceClient, - platformAuthProvider, - platformAuthType + platformAuthProvider ); } const authCodeRequest: CommonAuthorizationCodeRequest = { @@ -411,8 +406,7 @@ export async function handleResponseEAR( eventHandler: EventHandler, logger: Logger, performanceClient: IPerformanceClient, - platformAuthProvider?: NativeMessageHandler | PlatformDOMHandler, - platformAuthType?: string + platformAuthProvider?: IPlatformBrokerHandler ): Promise { // Remove throttle if it exists ThrottlingUtils.removeThrottle( @@ -459,8 +453,7 @@ export async function handleResponseEAR( eventHandler, logger, performanceClient, - platformAuthProvider, - platformAuthType + platformAuthProvider ); } diff --git a/lib/msal-browser/src/utils/BrowserConstants.ts b/lib/msal-browser/src/utils/BrowserConstants.ts index 0d43ab59c3..c8c1ed6af2 100644 --- a/lib/msal-browser/src/utils/BrowserConstants.ts +++ b/lib/msal-browser/src/utils/BrowserConstants.ts @@ -46,6 +46,8 @@ export const NativeConstants = { PREFERRED_EXTENSION_ID: "ppnbnpeolgkicgegkbkbjmhlideopiji", MATS_TELEMETRY: "MATS", MICROSOFT_ENTRA_BROKERID: "MicrosoftEntra", + PLATFORM_DOM_PROVIDER: "PlatformDOMHandler", + PLATFORM_EXTENSION_PROVIDER: "NativeMessageHandler", }; export const NativeExtensionMethod = { From 0811338df62618832d069790eea9e9e3d39f14fd Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Fri, 2 May 2025 12:36:21 -0700 Subject: [PATCH 12/30] added IPlatformAuthHandler interface and renamed Native to PlatformAuth --- ...okerHandler.ts => IPlatformAuthHandler.ts} | 8 +- .../broker/nativeBroker/NativeStatusCodes.ts | 4 - ...OMHandler.ts => PlatformAuthDOMHandler.ts} | 12 +-- ...ler.ts => PlatformAuthExtensionHandler.ts} | 18 ++-- .../nativeBroker/PlatformAuthProvider.ts | 10 +-- ...iveRequest.ts => PlatformBrokerRequest.ts} | 0 ...eResponse.ts => PlatformBrokerResponse.ts} | 0 .../src/cache/BrowserCacheManager.ts | 2 +- .../src/controllers/StandardController.ts | 24 +++--- .../BaseInteractionClient.ts | 6 +- ...nt.ts => PlatformAuthInteractionClient.ts} | 12 +-- .../src/interaction_client/PopupClient.ts | 5 +- .../src/interaction_client/RedirectClient.ts | 4 +- .../SilentAuthCodeClient.ts | 4 +- .../interaction_client/SilentIframeClient.ts | 4 +- lib/msal-browser/src/protocol/Authorize.ts | 12 +-- .../test/app/PublicClientApplication.spec.ts | 86 +++++++++++-------- .../test/broker/NativeMessageHandler.spec.ts | 55 +++++++----- .../NativeInteractionClient.spec.ts | 84 +++++++++--------- .../interaction_client/PopupClient.spec.ts | 10 +-- .../interaction_client/RedirectClient.spec.ts | 8 +- .../SilentIframeClient.spec.ts | 10 +-- .../test/protocol/Authorize.spec.ts | 11 ++- .../test/utils/StringConstants.ts | 2 +- 24 files changed, 205 insertions(+), 186 deletions(-) rename lib/msal-browser/src/broker/nativeBroker/{IPlatformBrokerHandler.ts => IPlatformAuthHandler.ts} (57%) rename lib/msal-browser/src/broker/nativeBroker/{PlatformDOMHandler.ts => PlatformAuthDOMHandler.ts} (95%) rename lib/msal-browser/src/broker/nativeBroker/{NativeMessageHandler.ts => PlatformAuthExtensionHandler.ts} (96%) rename lib/msal-browser/src/broker/nativeBroker/{NativeRequest.ts => PlatformBrokerRequest.ts} (100%) rename lib/msal-browser/src/broker/nativeBroker/{NativeResponse.ts => PlatformBrokerResponse.ts} (100%) rename lib/msal-browser/src/interaction_client/{NativeInteractionClient.ts => PlatformAuthInteractionClient.ts} (99%) diff --git a/lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts b/lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts similarity index 57% rename from lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts rename to lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts index 4a297e2052..4c4f81c2ee 100644 --- a/lib/msal-browser/src/broker/nativeBroker/IPlatformBrokerHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts @@ -3,17 +3,17 @@ * Licensed under the MIT License. */ -import { PlatformBrokerRequest } from "./NativeRequest.js"; -import { PlatformBrokerResponse } from "./NativeResponse.js"; +import { PlatformBrokerRequest } from "./PlatformBrokerRequest.js"; +import { PlatformBrokerResponse } from "./PlatformBrokerResponse.js"; /** * Interface for the Platform Broker Handlers */ -export interface IPlatformBrokerHandler { +export interface IPlatformAuthHandler { getExtensionId(): string | undefined; getExtensionVersion(): string | undefined; sendMessage( request: PlatformBrokerRequest ): Promise; - validateNativeResponse(response: object): PlatformBrokerResponse; + validatePlatformBrokerResponse(response: object): PlatformBrokerResponse; } diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts b/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts index eec25946ab..a7d42e8ac1 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts +++ b/lib/msal-browser/src/broker/nativeBroker/NativeStatusCodes.ts @@ -11,7 +11,3 @@ export const TRANSIENT_ERROR = "TRANSIENT_ERROR"; export const PERSISTENT_ERROR = "PERSISTENT_ERROR"; export const DISABLED = "DISABLED"; export const ACCOUNT_UNAVAILABLE = "ACCOUNT_UNAVAILABLE"; - -// Status codes that can be thrown by the Platform Broker via DOM APIs -export const UI_NOT_ALLOWED = "UI_NOT_ALLOWED"; -export const THROTTLED = "THROTTLED"; diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts similarity index 95% rename from lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts rename to lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index b93c6d41c7..d602a8f4e1 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -13,17 +13,17 @@ import { import { PlatformBrokerRequest, PlatformDOMTokenRequest, -} from "./NativeRequest.js"; +} from "./PlatformBrokerRequest.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; import { PlatformBrokerResponse, PlatformDOMTokenResponse, -} from "./NativeResponse.js"; +} from "./PlatformBrokerResponse.js"; import { createNativeAuthError } from "../../error/NativeAuthError.js"; -import { IPlatformBrokerHandler } from "./IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js"; -export class PlatformDOMHandler implements IPlatformBrokerHandler { +export class PlatformAuthDOMHandler implements IPlatformAuthHandler { protected logger: Logger; protected performanceClient: IPerformanceClient; protected correlationId: string; @@ -90,7 +90,7 @@ export class PlatformDOMHandler implements IPlatformBrokerHandler { await window.navigator.platformAuthentication.executeGetToken( platformDOMRequest ); - return this.validateNativeResponse(response); + return this.validatePlatformBrokerResponse(response); } catch (e) { this.logger.error( "PlatformDOMHandler: executeGetToken DOM API error" @@ -141,7 +141,7 @@ export class PlatformDOMHandler implements IPlatformBrokerHandler { return platformDOMRequest; } - validateNativeResponse(response: object): PlatformBrokerResponse { + validatePlatformBrokerResponse(response: object): PlatformBrokerResponse { if (response.hasOwnProperty("isSuccess")) { if ( response.hasOwnProperty("access_token") && diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts similarity index 96% rename from lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts rename to lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts index b3bc0779b2..156dfd51b3 100644 --- a/lib/msal-browser/src/broker/nativeBroker/NativeMessageHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts @@ -20,15 +20,15 @@ import { NativeExtensionRequest, NativeExtensionRequestBody, PlatformBrokerRequest, -} from "./NativeRequest.js"; +} from "./PlatformBrokerRequest.js"; import { createNativeAuthError } from "../../error/NativeAuthError.js"; import { createBrowserAuthError, BrowserAuthErrorCodes, } from "../../error/BrowserAuthError.js"; import { createNewGuid } from "../../crypto/BrowserCrypto.js"; -import { PlatformBrokerResponse } from "./NativeResponse.js"; -import { IPlatformBrokerHandler } from "./IPlatformBrokerHandler.js"; +import { PlatformBrokerResponse } from "./PlatformBrokerResponse.js"; +import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js"; type ResponseResolvers = { resolve: (value: T | PromiseLike) => void; @@ -37,7 +37,7 @@ type ResponseResolvers = { ) => void; }; -export class NativeMessageHandler implements IPlatformBrokerHandler { +export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { private extensionId: string | undefined; private extensionVersion: string | undefined; private logger: Logger; @@ -110,7 +110,7 @@ export class NativeMessageHandler implements IPlatformBrokerHandler { }); const validatedResponse: PlatformBrokerResponse = - this.validateNativeResponse(response); + this.validatePlatformBrokerResponse(response); return validatedResponse; } @@ -126,10 +126,10 @@ export class NativeMessageHandler implements IPlatformBrokerHandler { logger: Logger, handshakeTimeoutMs: number, performanceClient: IPerformanceClient - ): Promise { + ): Promise { logger.trace("NativeMessageHandler - createProvider called."); try { - const preferredProvider = new NativeMessageHandler( + const preferredProvider = new PlatformAuthExtensionHandler( logger, handshakeTimeoutMs, performanceClient, @@ -139,7 +139,7 @@ export class NativeMessageHandler implements IPlatformBrokerHandler { return preferredProvider; } catch (e) { // If preferred extension fails for whatever reason, fallback to using any installed extension - const backupProvider = new NativeMessageHandler( + const backupProvider = new PlatformAuthExtensionHandler( logger, handshakeTimeoutMs, performanceClient @@ -372,7 +372,7 @@ export class NativeMessageHandler implements IPlatformBrokerHandler { * Validates native platform response before processing * @param response */ - validateNativeResponse(response: object): PlatformBrokerResponse { + validatePlatformBrokerResponse(response: object): PlatformBrokerResponse { if ( response.hasOwnProperty("access_token") && response.hasOwnProperty("id_token") && diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index d6b863edbc..e0c678e24a 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -15,9 +15,9 @@ import { DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, } from "../../config/Configuration.js"; import { BrowserPerformanceClient } from "../../telemetry/BrowserPerformanceClient.js"; -import { NativeMessageHandler } from "./NativeMessageHandler.js"; +import { PlatformAuthExtensionHandler } from "./PlatformAuthExtensionHandler.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; -import { IPlatformBrokerHandler } from "./IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js"; /** * Checks if the platform broker is available in the current environment. @@ -66,7 +66,7 @@ export async function isPlatformBrokerAvailable( // Check and initialize native extension provider if available try { const nativeExtensionProvider = - await NativeMessageHandler.createProvider( + await PlatformAuthExtensionHandler.createProvider( logger, DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, performanceClient @@ -96,7 +96,7 @@ export async function isPlatformBrokerAvailable( export function isBrokerAvailable( config: BrowserConfiguration, logger: Logger, - platformAuthProvider?: IPlatformBrokerHandler, + platformAuthProvider?: IPlatformAuthHandler, authenticationScheme?: AuthenticationScheme ): boolean { logger.trace("isBrokerAvailable called"); @@ -112,7 +112,7 @@ export function isBrokerAvailable( logger.trace( "isBrokerAvailable: Platform auth provider is not initialized, returning false" ); - // Extension is not available + // Platform broker auth providers are not available return false; } diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformBrokerRequest.ts similarity index 100% rename from lib/msal-browser/src/broker/nativeBroker/NativeRequest.ts rename to lib/msal-browser/src/broker/nativeBroker/PlatformBrokerRequest.ts diff --git a/lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformBrokerResponse.ts similarity index 100% rename from lib/msal-browser/src/broker/nativeBroker/NativeResponse.ts rename to lib/msal-browser/src/broker/nativeBroker/PlatformBrokerResponse.ts diff --git a/lib/msal-browser/src/cache/BrowserCacheManager.ts b/lib/msal-browser/src/cache/BrowserCacheManager.ts index 8aa7d42f55..b7e8b710cb 100644 --- a/lib/msal-browser/src/cache/BrowserCacheManager.ts +++ b/lib/msal-browser/src/cache/BrowserCacheManager.ts @@ -53,7 +53,7 @@ import { LocalStorage } from "./LocalStorage.js"; import { SessionStorage } from "./SessionStorage.js"; import { MemoryStorage } from "./MemoryStorage.js"; import { IWindowStorage } from "./IWindowStorage.js"; -import { PlatformBrokerRequest } from "../broker/nativeBroker/NativeRequest.js"; +import { PlatformBrokerRequest } from "../broker/nativeBroker/PlatformBrokerRequest.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { SilentRequest } from "../request/SilentRequest.js"; import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 48381b5b43..e11535de38 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -64,8 +64,8 @@ import { SilentIframeClient } from "../interaction_client/SilentIframeClient.js" import { SilentRefreshClient } from "../interaction_client/SilentRefreshClient.js"; import { TokenCache } from "../cache/TokenCache.js"; import { ITokenCache } from "../cache/ITokenCache.js"; -import { NativeInteractionClient } from "../interaction_client/NativeInteractionClient.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; +import { PlatformAuthInteractionClient } from "../interaction_client/PlatformAuthInteractionClient.js"; +import { PlatformAuthExtensionHandler } from "../broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { SilentRequest } from "../request/SilentRequest.js"; import { NativeAuthError, @@ -78,7 +78,7 @@ import { BrowserAuthErrorCodes, } from "../error/BrowserAuthError.js"; import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js"; -import { PlatformBrokerRequest } from "../broker/nativeBroker/NativeRequest.js"; +import { PlatformBrokerRequest } from "../broker/nativeBroker/PlatformBrokerRequest.js"; import { StandardOperatingContext } from "../operatingcontext/StandardOperatingContext.js"; import { BaseOperatingContext } from "../operatingcontext/BaseOperatingContext.js"; import { IController } from "./IController.js"; @@ -88,10 +88,10 @@ import { createNewGuid } from "../crypto/BrowserCrypto.js"; import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { PlatformDOMHandler } from "../broker/nativeBroker/PlatformDOMHandler.js"; +import { PlatformAuthDOMHandler } from "../broker/nativeBroker/PlatformAuthDOMHandler.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; function getAccountType( account?: AccountInfo @@ -164,7 +164,7 @@ export class StandardController implements IController { >; // Native Extension Provider - protected platformAuthProvider: IPlatformBrokerHandler | undefined; + protected platformAuthProvider: IPlatformAuthHandler | undefined; // Hybrid auth code responses private hybridAuthCodeResponses: Map>; @@ -403,7 +403,7 @@ export class StandardController implements IController { this.platformAuthProvider = domPlatformApiSupported; } else { this.platformAuthProvider = - await NativeMessageHandler.createProvider( + await PlatformAuthExtensionHandler.createProvider( this.logger, this.config.system.nativeBrokerHandshakeTimeout, this.performanceClient @@ -419,7 +419,7 @@ export class StandardController implements IController { protected async checkDOMPlatformSupport( correlationId?: string, brokerId?: string - ): Promise { + ): Promise { this.logger.trace("checkDOMPlatformSupport called", correlationId); if (!this.featureSupportConfig.enablePlatformBrokerDOMSupport) { @@ -447,7 +447,7 @@ export class StandardController implements IController { "Platform API available in DOM", correlationId ); - return new PlatformDOMHandler( + return new PlatformAuthDOMHandler( this.logger, this.performanceClient, brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID, @@ -555,7 +555,7 @@ export class StandardController implements IController { this.logger.trace( "handleRedirectPromise - acquiring token from native platform" ); - const nativeClient = new NativeInteractionClient( + const nativeClient = new PlatformAuthInteractionClient( this.config, this.browserStorage, this.browserCrypto, @@ -771,7 +771,7 @@ export class StandardController implements IController { this.platformAuthProvider && this.canUsePlatformBroker(request) ) { - const nativeClient = new NativeInteractionClient( + const nativeClient = new PlatformAuthInteractionClient( this.config, this.browserStorage, this.browserCrypto, @@ -1641,7 +1641,7 @@ export class StandardController implements IController { ); } - const nativeClient = new NativeInteractionClient( + const nativeClient = new PlatformAuthInteractionClient( this.config, this.browserStorage, this.browserCrypto, diff --git a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts index 615961952f..de519d660f 100644 --- a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts @@ -37,7 +37,7 @@ import { INavigationClient } from "../navigation/INavigationClient.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { ClearCacheRequest } from "../request/ClearCacheRequest.js"; import { createNewGuid } from "../crypto/BrowserCrypto.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; export abstract class BaseInteractionClient { protected config: BrowserConfiguration; @@ -47,7 +47,7 @@ export abstract class BaseInteractionClient { protected logger: Logger; protected eventHandler: EventHandler; protected navigationClient: INavigationClient; - protected platformAuthProvider: IPlatformBrokerHandler | undefined; + protected platformAuthProvider: IPlatformAuthHandler | undefined; protected correlationId: string; protected performanceClient: IPerformanceClient; @@ -59,7 +59,7 @@ export abstract class BaseInteractionClient { eventHandler: EventHandler, navigationClient: INavigationClient, performanceClient: IPerformanceClient, - platformAuthProvider?: IPlatformBrokerHandler, + platformAuthProvider?: IPlatformAuthHandler, correlationId?: string ) { this.config = config; diff --git a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts b/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts similarity index 99% rename from lib/msal-browser/src/interaction_client/NativeInteractionClient.ts rename to lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts index dcd01fbb51..388b2f6bcb 100644 --- a/lib/msal-browser/src/interaction_client/NativeInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts @@ -53,11 +53,11 @@ import { import { PlatformBrokerRequest, PlatformDOMTokenRequest, -} from "../broker/nativeBroker/NativeRequest.js"; +} from "../broker/nativeBroker/PlatformBrokerRequest.js"; import { MATS, PlatformBrokerResponse, -} from "../broker/nativeBroker/NativeResponse.js"; +} from "../broker/nativeBroker/PlatformBrokerResponse.js"; import { NativeAuthError, NativeAuthErrorCodes, @@ -75,12 +75,12 @@ import { SilentCacheClient } from "./SilentCacheClient.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { base64Decode } from "../encode/Base64Decode.js"; import { version } from "../packageMetadata.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; -export class NativeInteractionClient extends BaseInteractionClient { +export class PlatformAuthInteractionClient extends BaseInteractionClient { protected apiId: ApiId; protected accountId: string; - protected platformAuthProvider: IPlatformBrokerHandler; + protected platformAuthProvider: IPlatformAuthHandler; protected silentCacheClient: SilentCacheClient; protected nativeStorageManager: BrowserCacheManager; protected skus: string; @@ -94,7 +94,7 @@ export class NativeInteractionClient extends BaseInteractionClient { navigationClient: INavigationClient, apiId: ApiId, performanceClient: IPerformanceClient, - provider: IPlatformBrokerHandler, + provider: IPlatformAuthHandler, accountId: string, nativeStorageImpl: BrowserCacheManager, correlationId?: string diff --git a/lib/msal-browser/src/interaction_client/PopupClient.ts b/lib/msal-browser/src/interaction_client/PopupClient.ts index 03afbed582..a8e0e59d5d 100644 --- a/lib/msal-browser/src/interaction_client/PopupClient.ts +++ b/lib/msal-browser/src/interaction_client/PopupClient.ts @@ -31,7 +31,6 @@ import { EndSessionPopupRequest } from "../request/EndSessionPopupRequest.js"; import { NavigationOptions } from "../navigation/NavigationOptions.js"; import * as BrowserUtils from "../utils/BrowserUtils.js"; import { PopupRequest } from "../request/PopupRequest.js"; -import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler.js"; import { createBrowserAuthError, BrowserAuthErrorCodes, @@ -48,7 +47,7 @@ import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; export type PopupParams = { popup?: Window | null; @@ -70,7 +69,7 @@ export class PopupClient extends StandardInteractionClient { navigationClient: INavigationClient, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - platformAuthHandler?: IPlatformBrokerHandler, + platformAuthHandler?: IPlatformAuthHandler, correlationId?: string ) { super( diff --git a/lib/msal-browser/src/interaction_client/RedirectClient.ts b/lib/msal-browser/src/interaction_client/RedirectClient.ts index bda721945e..c6bcc89684 100644 --- a/lib/msal-browser/src/interaction_client/RedirectClient.ts +++ b/lib/msal-browser/src/interaction_client/RedirectClient.ts @@ -48,7 +48,7 @@ import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; function getNavigationType(): NavigationTimingType | undefined { if ( @@ -78,7 +78,7 @@ export class RedirectClient extends StandardInteractionClient { navigationClient: INavigationClient, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - platformAuthHandler?: IPlatformBrokerHandler, + platformAuthHandler?: IPlatformAuthHandler, correlationId?: string ) { super( diff --git a/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts b/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts index 212a4ff725..53da018ba4 100644 --- a/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentAuthCodeClient.ts @@ -27,7 +27,7 @@ import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest.js import { HybridSpaAuthorizationCodeClient } from "./HybridSpaAuthorizationCodeClient.js"; import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { InteractionHandler } from "../interaction_handler/InteractionHandler.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; export class SilentAuthCodeClient extends StandardInteractionClient { private apiId: ApiId; @@ -41,7 +41,7 @@ export class SilentAuthCodeClient extends StandardInteractionClient { navigationClient: INavigationClient, apiId: ApiId, performanceClient: IPerformanceClient, - platformAuthProvider?: IPlatformBrokerHandler, + platformAuthProvider?: IPlatformAuthHandler, correlationId?: string ) { super( diff --git a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts index 3c452c4f3c..0f91dd88bd 100644 --- a/lib/msal-browser/src/interaction_client/SilentIframeClient.ts +++ b/lib/msal-browser/src/interaction_client/SilentIframeClient.ts @@ -43,7 +43,7 @@ import * as Authorize from "../protocol/Authorize.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; import { generateEarKey } from "../crypto/BrowserCrypto.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; export class SilentIframeClient extends StandardInteractionClient { protected apiId: ApiId; @@ -59,7 +59,7 @@ export class SilentIframeClient extends StandardInteractionClient { apiId: ApiId, performanceClient: IPerformanceClient, nativeStorageImpl: BrowserCacheManager, - platformAuthProvider?: IPlatformBrokerHandler, + platformAuthProvider?: IPlatformAuthHandler, correlationId?: string ) { super( diff --git a/lib/msal-browser/src/protocol/Authorize.ts b/lib/msal-browser/src/protocol/Authorize.ts index 808ca374e4..a1d7c30313 100644 --- a/lib/msal-browser/src/protocol/Authorize.ts +++ b/lib/msal-browser/src/protocol/Authorize.ts @@ -40,10 +40,10 @@ import { import { AuthenticationResult } from "../response/AuthenticationResult.js"; import { InteractionHandler } from "../interaction_handler/InteractionHandler.js"; import { BrowserCacheManager } from "../cache/BrowserCacheManager.js"; -import { NativeInteractionClient } from "../interaction_client/NativeInteractionClient.js"; +import { PlatformAuthInteractionClient } from "../interaction_client/PlatformAuthInteractionClient.js"; import { EventHandler } from "../event/EventHandler.js"; import { decryptEarResponse } from "../crypto/BrowserCrypto.js"; -import { IPlatformBrokerHandler } from "../broker/nativeBroker/IPlatformBrokerHandler.js"; +import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; /** * Returns map of parameters that are applicable to all calls to /authorize whether using PKCE or EAR @@ -263,7 +263,7 @@ export async function handleResponsePlatformBroker( eventHandler: EventHandler, logger: Logger, performanceClient: IPerformanceClient, - platformAuthProvider?: IPlatformBrokerHandler + platformAuthProvider?: IPlatformAuthHandler ): Promise { logger.verbose("Account id found, calling WAM for token"); @@ -273,7 +273,7 @@ export async function handleResponsePlatformBroker( ); } const browserCrypto = new CryptoOps(logger, performanceClient); - const nativeInteractionClient = new NativeInteractionClient( + const nativeInteractionClient = new PlatformAuthInteractionClient( config, browserStorage, browserCrypto, @@ -327,7 +327,7 @@ export async function handleResponseCode( eventHandler: EventHandler, logger: Logger, performanceClient: IPerformanceClient, - platformAuthProvider?: IPlatformBrokerHandler + platformAuthProvider?: IPlatformAuthHandler ): Promise { // Remove throttle if it exists ThrottlingUtils.removeThrottle( @@ -406,7 +406,7 @@ export async function handleResponseEAR( eventHandler: EventHandler, logger: Logger, performanceClient: IPerformanceClient, - platformAuthProvider?: IPlatformBrokerHandler + platformAuthProvider?: IPlatformAuthHandler ): Promise { // Remove throttle if it exists ThrottlingUtils.removeThrottle( diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index f2f63440d3..d06fd78b22 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -95,9 +95,9 @@ import { } from "../../src/index.js"; import { SilentAuthCodeClient } from "../../src/interaction_client/SilentAuthCodeClient.js"; import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; -import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; -import { PlatformBrokerRequest } from "../../src/broker/nativeBroker/NativeRequest.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; +import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; +import { PlatformBrokerRequest } from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; import { NativeAuthError } from "../../src/error/NativeAuthError.js"; import { StandardController } from "../../src/controllers/StandardController.js"; import { AuthenticationResult } from "../../src/response/AuthenticationResult.js"; @@ -148,9 +148,9 @@ function stubProvider(config: Configuration) { const performanceClient = newConfig.telemetry.client; return jest - .spyOn(NativeMessageHandler, "createProvider") + .spyOn(PlatformAuthExtensionHandler, "createProvider") .mockImplementation(async () => { - return new NativeMessageHandler( + return new PlatformAuthExtensionHandler( logger, 2000, performanceClient, @@ -275,7 +275,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ); // @ts-ignore const handshakeSpy: jest.SpyInstance = jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, // @ts-ignore "sendHandshakeRequest" ); @@ -328,7 +328,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { // @ts-ignore expect( (apps[i] as any).controller.getNativeExtensionProvider() - ).toBeInstanceOf(NativeMessageHandler); + ).toBeInstanceOf(PlatformAuthExtensionHandler); } } finally { for (const port of ports) { @@ -365,7 +365,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ); // @ts-ignore const createProviderSpy: jest.SpyInstance = jest.spyOn( - NativeMessageHandler, + PlatformAuthExtensionHandler, "createProvider" ); @@ -458,13 +458,13 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(createProviderSpy).toHaveBeenCalled(); // @ts-ignore expect(pca.nativeExtensionProvider).toBeInstanceOf( - NativeMessageHandler + PlatformAuthExtensionHandler ); }); it("does not create extension provider if allowPlatformBroker is false", async () => { const createProviderSpy = jest.spyOn( - NativeMessageHandler, + PlatformAuthExtensionHandler, "createProvider" ); pca = new PublicClientApplication({ @@ -487,7 +487,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { it("catches error if extension provider fails to initialize", async () => { const createProviderSpy = jest - .spyOn(NativeMessageHandler, "createProvider") + .spyOn(PlatformAuthExtensionHandler, "createProvider") .mockRejectedValue(new Error("testError")); pca = new PublicClientApplication({ auth: { @@ -788,7 +788,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ); const redirectClientSpy: jest.SpyInstance = jest .spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "handleRedirectPromise" ) .mockImplementation(() => { @@ -909,7 +909,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { testAccount, ]); jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "handleRedirectPromise" ).mockResolvedValue(testTokenResponse); @@ -950,7 +950,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ); const redirectClientSpy: jest.SpyInstance = jest .spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "handleRedirectPromise" ) .mockRejectedValue(new Error("testerror")); @@ -1550,7 +1550,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { const nativeAcquireTokenSpy = jest .spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireTokenRedirect" ) .mockResolvedValue(); @@ -1638,7 +1638,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy = jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireTokenRedirect" ); const redirectSpy: jest.SpyInstance = jest @@ -1683,7 +1683,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { const nativeAcquireTokenSpy: jest.SpyInstance = jest .spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireTokenRedirect" ) .mockRejectedValue( @@ -1730,7 +1730,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { const nativeAcquireTokenSpy: jest.SpyInstance = jest .spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireTokenRedirect" ) .mockRejectedValue( @@ -1778,7 +1778,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { const nativeAcquireTokenSpy: jest.SpyInstance = jest .spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireTokenRedirect" ) .mockRejectedValue(new Error("testError")); @@ -2511,7 +2511,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ); const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockImplementation(async (request) => { expect(request.correlationId).toBe(RANDOM_TEST_GUID); return testTokenResponse; @@ -2567,7 +2567,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ); const popupSpy: jest.SpyInstance = jest @@ -2625,7 +2625,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue( new NativeAuthError("ContentError", "error in extension") ); @@ -2683,7 +2683,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockImplementation(() => { throw createInteractionRequiredAuthError( InteractionRequiredAuthErrorCodes.nativeAccountUnavailable @@ -2729,7 +2729,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue(new Error("testError")); const popupSpy: jest.SpyInstance = jest .spyOn(PopupClient.prototype, "acquireToken") @@ -3296,7 +3296,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockResolvedValue(testTokenResponse); const silentSpy: jest.SpyInstance = jest .spyOn(SilentIframeClient.prototype, "acquireToken") @@ -3353,7 +3353,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue( new NativeAuthError("ContentError", "error in extension") ); @@ -3397,7 +3397,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue(new Error("testError")); const silentSpy: jest.SpyInstance = jest .spyOn(SilentIframeClient.prototype, "acquireToken") @@ -3702,7 +3702,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockResolvedValue(testTokenResponse); const response = await pca.acquireTokenByCode({ scopes: ["User.Read"], @@ -3731,7 +3731,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { pca = (pca as any).controller; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue( new NativeAuthError( "ContentError", @@ -3762,7 +3762,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { await pca.initialize(); const nativeAcquireTokenSpy = jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ); @@ -4199,7 +4199,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockResolvedValue(testTokenResponse); const silentSpy: jest.SpyInstance = jest .spyOn(SilentIframeClient.prototype, "acquireToken") @@ -4256,7 +4256,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue( new NativeAuthError("ContentError", "error in extension") ); @@ -4301,7 +4301,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn(PlatformAuthInteractionClient.prototype, "acquireToken") .mockRejectedValue(new Error("testError")); const silentSpy: jest.SpyInstance = jest .spyOn(SilentIframeClient.prototype, "acquireToken") @@ -6143,10 +6143,16 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { .mockImplementation(); const isPlatformBrokerAvailableSpy = jest - .spyOn(NativeMessageHandler, "isPlatformBrokerAvailable") + .spyOn( + PlatformAuthExtensionHandler, + "isPlatformBrokerAvailable" + ) .mockReturnValue(true); const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn( + PlatformAuthInteractionClient.prototype, + "acquireToken" + ) .mockImplementation(); const cacheAccount = testAccount; cacheAccount.nativeAccountId = "nativeAccountId"; @@ -6207,13 +6213,19 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { .spyOn(SilentIframeClient.prototype, "acquireToken") .mockImplementation(); const nativeAcquireTokenSpy: jest.SpyInstance = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn( + PlatformAuthInteractionClient.prototype, + "acquireToken" + ) .mockImplementation(); const cacheAccount = testAccount; cacheAccount.nativeAccountId = "nativeAccountId"; const isPlatformBrokerAvailableSpy = jest - .spyOn(NativeMessageHandler, "isPlatformBrokerAvailable") + .spyOn( + PlatformAuthExtensionHandler, + "isPlatformBrokerAvailable" + ) .mockReturnValue(true); testAccount.nativeAccountId = "nativeAccountId"; diff --git a/lib/msal-browser/test/broker/NativeMessageHandler.spec.ts b/lib/msal-browser/test/broker/NativeMessageHandler.spec.ts index b567607a1b..6ce75bea59 100644 --- a/lib/msal-browser/test/broker/NativeMessageHandler.spec.ts +++ b/lib/msal-browser/test/broker/NativeMessageHandler.spec.ts @@ -9,7 +9,7 @@ import { AuthErrorMessage, IPerformanceClient, } from "@azure/msal-common"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { BrowserAuthError, BrowserAuthErrorMessage } from "../../src/index.js"; import { NativeExtensionMethod } from "../../src/utils/BrowserConstants.js"; import { NativeAuthError } from "../../src/error/NativeAuthError.js"; @@ -61,12 +61,15 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - const wamMessageHandler = await NativeMessageHandler.createProvider( - new Logger({}), - 2000, - performanceClient + const wamMessageHandler = + await PlatformAuthExtensionHandler.createProvider( + new Logger({}), + 2000, + performanceClient + ); + expect(wamMessageHandler).toBeInstanceOf( + PlatformAuthExtensionHandler ); - expect(wamMessageHandler).toBeInstanceOf(NativeMessageHandler); window.removeEventListener("message", eventHandler, true); }); @@ -110,7 +113,7 @@ describe("NativeMessageHandler Tests", () => { } ); - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient @@ -147,18 +150,21 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - const wamMessageHandler = await NativeMessageHandler.createProvider( - new Logger({}), - 2000, - performanceClient + const wamMessageHandler = + await PlatformAuthExtensionHandler.createProvider( + new Logger({}), + 2000, + performanceClient + ); + expect(wamMessageHandler).toBeInstanceOf( + PlatformAuthExtensionHandler ); - expect(wamMessageHandler).toBeInstanceOf(NativeMessageHandler); window.removeEventListener("message", eventHandler, true); }); it("Throws if no extension is installed", (done) => { - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient @@ -181,7 +187,7 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient @@ -219,7 +225,7 @@ describe("NativeMessageHandler Tests", () => { } ); - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient @@ -275,12 +281,15 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - const wamMessageHandler = await NativeMessageHandler.createProvider( - new Logger({}), - 2000, - performanceClient + const wamMessageHandler = + await PlatformAuthExtensionHandler.createProvider( + new Logger({}), + 2000, + performanceClient + ); + expect(wamMessageHandler).toBeInstanceOf( + PlatformAuthExtensionHandler ); - expect(wamMessageHandler).toBeInstanceOf(NativeMessageHandler); const response = await wamMessageHandler.sendMessage({ method: NativeExtensionMethod.GetToken, @@ -332,7 +341,7 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient @@ -398,7 +407,7 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient @@ -462,7 +471,7 @@ describe("NativeMessageHandler Tests", () => { window.addEventListener("message", eventHandler, true); - NativeMessageHandler.createProvider( + PlatformAuthExtensionHandler.createProvider( new Logger({}), 2000, performanceClient diff --git a/lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts b/lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts index 463a6692be..c9e325e376 100644 --- a/lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts +++ b/lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts @@ -21,9 +21,9 @@ import { InProgressPerformanceEvent, PerformanceEvents, } from "@azure/msal-common"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { ApiId } from "../../src/utils/BrowserConstants.js"; -import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; +import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; import { PublicClientApplication } from "../../src/app/PublicClientApplication.js"; import { ID_TOKEN_CLAIMS, @@ -39,7 +39,7 @@ import { NativeAuthErrorCodes, NativeAuthErrorMessages, } from "../../src/error/NativeAuthError.js"; -import { NativeExtensionRequestBody } from "../../src/broker/nativeBroker/NativeRequest.js"; +import { NativeExtensionRequestBody } from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; import { @@ -111,12 +111,12 @@ const testAccessTokenEntity: AccessTokenEntity = { describe("NativeInteractionClient Tests", () => { let pca: PublicClientApplication; - let nativeInteractionClient: NativeInteractionClient; + let nativeInteractionClient: PlatformAuthInteractionClient; let browserCacheManager: BrowserCacheManager; let internalStorage: BrowserCacheManager; - let wamProvider: NativeMessageHandler; + let wamProvider: PlatformAuthExtensionHandler; let postMessageSpy: jest.SpyInstance; let mcPort: MessagePort; let perfClient: IPerformanceClient; @@ -152,13 +152,13 @@ describe("NativeInteractionClient Tests", () => { //@ts-ignore internalStorage = pca.nativeInternalStorage; - wamProvider = new NativeMessageHandler( + wamProvider = new PlatformAuthExtensionHandler( pca.getLogger(), 2000, getDefaultPerformanceClient() ); - nativeInteractionClient = new NativeInteractionClient( + nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore pca.config, // @ts-ignore @@ -240,7 +240,7 @@ describe("NativeInteractionClient Tests", () => { describe("acquireToken Tests", () => { it("acquires token successfully", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -264,7 +264,7 @@ describe("NativeInteractionClient Tests", () => { it("acquires token successfully with string expires_in", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE_STRING_EXPIRES_IN); @@ -327,7 +327,7 @@ describe("NativeInteractionClient Tests", () => { it("prompt: none succeeds", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -352,7 +352,7 @@ describe("NativeInteractionClient Tests", () => { it("prompt: consent succeeds", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -377,7 +377,7 @@ describe("NativeInteractionClient Tests", () => { it("prompt: login succeeds", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -419,7 +419,7 @@ describe("NativeInteractionClient Tests", () => { ).mockReturnValue(TEST_ACCOUNT_INFO); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(mockWamResponse); @@ -465,7 +465,7 @@ describe("NativeInteractionClient Tests", () => { ).mockReturnValue(TEST_ACCOUNT_INFO); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(mockWamResponse); @@ -505,7 +505,7 @@ describe("NativeInteractionClient Tests", () => { ).mockReturnValue(TEST_ACCOUNT_INFO); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(mockWamResponse); @@ -538,7 +538,7 @@ describe("NativeInteractionClient Tests", () => { it("ssoSilent overwrites prompt to be 'none' and succeeds", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((nativeRequest): Promise => { expect( @@ -547,7 +547,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(MOCK_WAM_RESPONSE); }); // @ts-ignore - const nativeInteractionClient = new NativeInteractionClient( + const nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore pca.config, // @ts-ignore @@ -589,7 +589,7 @@ describe("NativeInteractionClient Tests", () => { it("acquireTokenSilent overwrites prompt to be 'none' and succeeds", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((nativeRequest): Promise => { expect( @@ -598,7 +598,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(MOCK_WAM_RESPONSE); }); // @ts-ignore - const nativeInteractionClient = new NativeInteractionClient( + const nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore pca.config, // @ts-ignore @@ -640,7 +640,7 @@ describe("NativeInteractionClient Tests", () => { it("adds MSAL.js SKU to request extra query parameters", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { expect( @@ -655,7 +655,7 @@ describe("NativeInteractionClient Tests", () => { it("adds MSAL.js and Chrome extension SKUs to request extra query parameters", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { expect( @@ -667,15 +667,15 @@ describe("NativeInteractionClient Tests", () => { }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "getExtensionId" ).mockReturnValue("ppnbnpeolgkicgegkbkbjmhlideopiji"); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "getExtensionVersion" ).mockReturnValue("1.0.2"); - nativeInteractionClient = new NativeInteractionClient( + nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore pca.config, // @ts-ignore @@ -703,7 +703,7 @@ describe("NativeInteractionClient Tests", () => { it("adds MSAL.js and unknown extension SKUs to request extra query parameters", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { expect( @@ -715,15 +715,15 @@ describe("NativeInteractionClient Tests", () => { }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "getExtensionId" ).mockReturnValue("random_extension_id"); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "getExtensionVersion" ).mockReturnValue("2.3.4"); - nativeInteractionClient = new NativeInteractionClient( + nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore pca.config, // @ts-ignore @@ -751,7 +751,7 @@ describe("NativeInteractionClient Tests", () => { it("does not set native broker error to server telemetry", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -775,7 +775,7 @@ describe("NativeInteractionClient Tests", () => { it("sets native broker error to server telemetry", async () => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { return Promise.reject( @@ -803,7 +803,7 @@ describe("NativeInteractionClient Tests", () => { it("resets native broker error in server telemetry", async () => { const sendMessageStub = jest - .spyOn(NativeMessageHandler.prototype, "sendMessage") + .spyOn(PlatformAuthExtensionHandler.prototype, "sendMessage") .mockImplementation(); sendMessageStub .mockImplementationOnce((message): Promise => { @@ -858,7 +858,7 @@ describe("NativeInteractionClient Tests", () => { beforeEach(() => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockResolvedValue(MOCK_WAM_RESPONSE); }); @@ -951,7 +951,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -973,7 +973,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -994,7 +994,7 @@ describe("NativeInteractionClient Tests", () => { it("throws if native token acquisition fails with fatal error", (done) => { jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.reject( @@ -1025,7 +1025,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { expect( @@ -1061,7 +1061,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((message): Promise => { return Promise.reject( @@ -1084,7 +1084,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); const sendMessageStub = jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ); sendMessageStub @@ -1151,7 +1151,7 @@ describe("NativeInteractionClient Tests", () => { it("should not include onRedirectNavigate call back function in request", (done) => { jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, // @ts-ignore "initializeNativeRequest" // @ts-ignore @@ -1182,7 +1182,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); @@ -1228,7 +1228,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation( (messageBody: NativeExtensionRequestBody): Promise => { @@ -1281,7 +1281,7 @@ describe("NativeInteractionClient Tests", () => { return Promise.resolve(true); }); jest.spyOn( - NativeMessageHandler.prototype, + PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); diff --git a/lib/msal-browser/test/interaction_client/PopupClient.spec.ts b/lib/msal-browser/test/interaction_client/PopupClient.spec.ts index e4b7aaf948..d149ce07f5 100644 --- a/lib/msal-browser/test/interaction_client/PopupClient.spec.ts +++ b/lib/msal-browser/test/interaction_client/PopupClient.spec.ts @@ -50,8 +50,8 @@ import * as AuthorizeProtocol from "../../src/protocol/Authorize.js"; import { NavigationClient } from "../../src/navigation/NavigationClient.js"; import { EndSessionPopupRequest } from "../../src/request/EndSessionPopupRequest.js"; import { PopupClient } from "../../src/interaction_client/PopupClient.js"; -import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; +import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { BrowserAuthError, createBrowserAuthError, @@ -391,7 +391,7 @@ describe("PopupClient", () => { TEST_HASHES.TEST_SUCCESS_NATIVE_ACCOUNT_ID_POPUP ); jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ).mockResolvedValue(testTokenResponse); jest.spyOn(PkceGenerator, "generatePkceCodes").mockResolvedValue({ @@ -401,7 +401,7 @@ describe("PopupClient", () => { jest.spyOn(BrowserCrypto, "createNewGuid").mockReturnValue( RANDOM_TEST_GUID ); - const nativeMessageHandler = new NativeMessageHandler( + const nativeMessageHandler = new PlatformAuthExtensionHandler( //@ts-ignore pca.logger, 2000, @@ -518,7 +518,7 @@ describe("PopupClient", () => { TEST_HASHES.TEST_SUCCESS_NATIVE_ACCOUNT_ID_POPUP ); jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ).mockResolvedValue(testTokenResponse); jest.spyOn(PkceGenerator, "generatePkceCodes").mockResolvedValue({ diff --git a/lib/msal-browser/test/interaction_client/RedirectClient.spec.ts b/lib/msal-browser/test/interaction_client/RedirectClient.spec.ts index 56e6a9075b..e4b240beae 100644 --- a/lib/msal-browser/test/interaction_client/RedirectClient.spec.ts +++ b/lib/msal-browser/test/interaction_client/RedirectClient.spec.ts @@ -77,8 +77,8 @@ import { NavigationOptions } from "../../src/navigation/NavigationOptions.js"; import { RedirectClient } from "../../src/interaction_client/RedirectClient.js"; import { EventHandler } from "../../src/event/EventHandler.js"; import { EventType } from "../../src/event/EventType.js"; -import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; +import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; import { AuthenticationResult } from "../../src/response/AuthenticationResult.js"; import { @@ -486,7 +486,7 @@ describe("RedirectClient", () => { pca = (pca as any).controller; // @ts-ignore - const nativeMessageHandler = new NativeMessageHandler( + const nativeMessageHandler = new PlatformAuthExtensionHandler( //@ts-ignore pca.logger, 2000, @@ -594,7 +594,7 @@ describe("RedirectClient", () => { } }); jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ).mockResolvedValue(testTokenResponse); diff --git a/lib/msal-browser/test/interaction_client/SilentIframeClient.spec.ts b/lib/msal-browser/test/interaction_client/SilentIframeClient.spec.ts index b144cf6c56..33a6a1a44a 100644 --- a/lib/msal-browser/test/interaction_client/SilentIframeClient.spec.ts +++ b/lib/msal-browser/test/interaction_client/SilentIframeClient.spec.ts @@ -42,8 +42,8 @@ import * as PkceGenerator from "../../src/crypto/PkceGenerator.js"; import * as AuthorizeProtocol from "../../src/protocol/Authorize.js"; import { SilentIframeClient } from "../../src/interaction_client/SilentIframeClient.js"; import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; -import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; +import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; import { InteractionHandler } from "../../src/interaction_handler/InteractionHandler.js"; import { @@ -413,7 +413,7 @@ describe("SilentIframeClient", () => { pca = (pca as any).controller; // @ts-ignore - const nativeMessageHandler = new NativeMessageHandler( + const nativeMessageHandler = new PlatformAuthExtensionHandler( //@ts-ignore pca.logger, 2000, @@ -491,7 +491,7 @@ describe("SilentIframeClient", () => { TEST_HASHES.TEST_SUCCESS_NATIVE_ACCOUNT_ID_SILENT ); jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ).mockResolvedValue(testTokenResponse); jest.spyOn(PkceGenerator, "generatePkceCodes").mockResolvedValue({ @@ -593,7 +593,7 @@ describe("SilentIframeClient", () => { TEST_HASHES.TEST_SUCCESS_NATIVE_ACCOUNT_ID_SILENT ); jest.spyOn( - NativeInteractionClient.prototype, + PlatformAuthInteractionClient.prototype, "acquireToken" ).mockResolvedValue(testTokenResponse); jest.spyOn(PkceGenerator, "generatePkceCodes").mockResolvedValue({ diff --git a/lib/msal-browser/test/protocol/Authorize.spec.ts b/lib/msal-browser/test/protocol/Authorize.spec.ts index f2650902e0..f5878c4255 100644 --- a/lib/msal-browser/test/protocol/Authorize.spec.ts +++ b/lib/msal-browser/test/protocol/Authorize.spec.ts @@ -33,8 +33,8 @@ import { BrowserAuthError, BrowserAuthErrorCodes, } from "../../src/error/BrowserAuthError.js"; -import { NativeMessageHandler } from "../../src/broker/nativeBroker/NativeMessageHandler.js"; -import { NativeInteractionClient } from "../../src/interaction_client/NativeInteractionClient.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; +import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; describe("Authorize Protocol Tests", () => { describe("EAR Protocol Tests", () => { @@ -295,13 +295,16 @@ describe("Authorize Protocol Tests", () => { ); const response = { ...validResponse, ear_jwe: jwe }; - const nativeMessageHandler = new NativeMessageHandler( + const nativeMessageHandler = new PlatformAuthExtensionHandler( logger, 2000, performanceClient ); const platformBrokerSpy = jest - .spyOn(NativeInteractionClient.prototype, "acquireToken") + .spyOn( + PlatformAuthInteractionClient.prototype, + "acquireToken" + ) .mockResolvedValue(getTestAuthenticationResult()); const authResult = await Authorize.handleResponseEAR( diff --git a/lib/msal-browser/test/utils/StringConstants.ts b/lib/msal-browser/test/utils/StringConstants.ts index 76d8fdf7cb..1c7896a738 100644 --- a/lib/msal-browser/test/utils/StringConstants.ts +++ b/lib/msal-browser/test/utils/StringConstants.ts @@ -16,7 +16,7 @@ import { version } from "../../src/packageMetadata.js"; import { base64Decode, base64DecToArr } from "../../src/encode/Base64Decode.js"; import { urlEncodeArr } from "../../src/encode/Base64Encode.js"; import { AuthenticationResult } from "../../src/response/AuthenticationResult.js"; -import { PlatformDOMTokenResponse } from "../../src/broker/nativeBroker/NativeResponse.js"; +import { PlatformDOMTokenResponse } from "../../src/broker/nativeBroker/PlatformBrokerResponse.js"; /** * This file contains the string constants used by the test classes. From fb078dc03aad2fed3c344a7e274fa800e16b4db2 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Fri, 2 May 2025 12:45:39 -0700 Subject: [PATCH 13/30] addressing comments --- .../src/broker/nativeBroker/PlatformAuthProvider.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index e0c678e24a..484c667ed5 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -63,7 +63,10 @@ export async function isPlatformBrokerAvailable( } } - // Check and initialize native extension provider if available + /* + * If DOM APIs are not available, check if browser extension is available. + * Platform authentication via DOM APIs is preferred over extension APIs. + */ try { const nativeExtensionProvider = await PlatformAuthExtensionHandler.createProvider( From 6feef52f618405b0bade861b346f550d29d5ecb2 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 5 May 2025 21:12:30 -0700 Subject: [PATCH 14/30] addressing comments --- .../nativeBroker/IPlatformAuthHandler.ts | 2 +- .../nativeBroker/PlatformAuthDOMHandler.ts | 58 ++++++++++---- .../PlatformAuthExtensionHandler.ts | 41 +++++++--- .../nativeBroker/PlatformAuthProvider.ts | 40 +++++----- .../src/controllers/StandardController.ts | 80 +++++-------------- .../PlatformAuthInteractionClient.ts | 11 +-- .../src/utils/BrowserConstants.ts | 1 + 7 files changed, 111 insertions(+), 122 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts b/lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts index 4c4f81c2ee..91d25aefdf 100644 --- a/lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/IPlatformAuthHandler.ts @@ -12,8 +12,8 @@ import { PlatformBrokerResponse } from "./PlatformBrokerResponse.js"; export interface IPlatformAuthHandler { getExtensionId(): string | undefined; getExtensionVersion(): string | undefined; + getExtensionName(): string | undefined; sendMessage( request: PlatformBrokerRequest ): Promise; - validatePlatformBrokerResponse(response: object): PlatformBrokerResponse; } diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index d602a8f4e1..ab32621ebb 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -45,6 +45,34 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { this.platformAuthType = NativeConstants.PLATFORM_DOM_PROVIDER; } + static async createProvider( + logger: Logger, + performanceClient: IPerformanceClient, + brokerId?: string + ): Promise { + logger.trace("PlatformAuthDOMHandler: createProvider called"); + + // @ts-ignore + if (window.navigator?.platformAuthentication) { + const supportedContracts = + // @ts-ignore + await window.navigator.platformAuthentication.getSupportedContracts( + brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID + ); + if ( + supportedContracts?.includes(NativeConstants.PLATFORM_DOM_APIS) + ) { + logger.trace("Platform auth api available in DOM"); + return new PlatformAuthDOMHandler( + logger, + performanceClient, + brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID + ); + } + } + return undefined; + } + /** * Returns the Id for the broker extension this handler is communicating with * @returns @@ -57,12 +85,11 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { * Gets the version of the browser this handler is communicating with */ getExtensionVersion(): string | undefined { - // @ts-ignore - const userAgent = window.navigator.userAgentData?.getHighEntropyValues([ - "uaFullVersion", - ]); - this.extensionVersion = userAgent ? userAgent["uaFullVersion"] : ""; - return this.extensionVersion; + return ""; + } + + getExtensionName(): string | undefined { + return this.brokerId; } /** @@ -76,11 +103,6 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { this.logger.trace( "PlatformDOMHandler - Sending request to browser DOM API" ); - this.logger.tracePii( - `PlatformDOMHandler - Sending request to browser DOM API: ${JSON.stringify( - request - )}` - ); try { const platformDOMRequest: PlatformDOMTokenRequest = @@ -130,7 +152,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { clientId: clientId, correlationId: correlationId || this.correlationId, extraParameters: { ...extraParameters, ...validExtraParameters }, - isSecurityTokenService: true, + isSecurityTokenService: false, redirectUri: redirectUri, scope: scope, state: state, @@ -141,15 +163,17 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { return platformDOMRequest; } - validatePlatformBrokerResponse(response: object): PlatformBrokerResponse { + private validatePlatformBrokerResponse( + response: object + ): PlatformBrokerResponse { if (response.hasOwnProperty("isSuccess")) { if ( - response.hasOwnProperty("access_token") && - response.hasOwnProperty("id_token") && - response.hasOwnProperty("client_info") && + response.hasOwnProperty("accessToken") && + response.hasOwnProperty("idToken") && + response.hasOwnProperty("clientInfo") && response.hasOwnProperty("account") && response.hasOwnProperty("scopes") && - response.hasOwnProperty("expires_in") + response.hasOwnProperty("expiresIn") ) { this.logger.trace( "PlatformDOMHandler: platform broker returned successful and valid response" diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts index 156dfd51b3..9d6cb0cfea 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts @@ -78,7 +78,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { async sendMessage( request: PlatformBrokerRequest ): Promise { - this.logger.trace("NativeMessageHandler - sendMessage called."); + this.logger.trace("PlatformAuthExtensionHandler - sendMessage called."); const { ...nativeTokenRequest } = request; @@ -96,10 +96,10 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { }; this.logger.trace( - "NativeMessageHandler - Sending request to browser extension" + "PlatformAuthExtensionHandler - Sending request to browser extension" ); this.logger.tracePii( - `NativeMessageHandler - Sending request to browser extension: ${JSON.stringify( + `PlatformAuthExtensionHandler - Sending request to browser extension: ${JSON.stringify( req )}` ); @@ -127,7 +127,8 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { handshakeTimeoutMs: number, performanceClient: IPerformanceClient ): Promise { - logger.trace("NativeMessageHandler - createProvider called."); + logger.trace("PlatformAuthExtensionHandler - createProvider called."); + try { const preferredProvider = new PlatformAuthExtensionHandler( logger, @@ -154,7 +155,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { */ private async sendHandshakeRequest(): Promise { this.logger.trace( - "NativeMessageHandler - sendHandshakeRequest called." + "PlatformAuthExtensionHandler - sendHandshakeRequest called." ); // Register this event listener before sending handshake window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first @@ -211,7 +212,9 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { * @param event */ private onWindowMessage(event: MessageEvent): void { - this.logger.trace("NativeMessageHandler - onWindowMessage called"); + this.logger.trace( + "PlatformAuthExtensionHandler - onWindowMessage called" + ); // We only accept messages from ourselves if (event.source !== window) { return; @@ -240,7 +243,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { */ if (!handshakeResolver) { this.logger.trace( - `NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}` + `PlatformAuthExtensionHandler.onWindowMessage - resolver can't be found for request ${request.responseId}` ); return; } @@ -272,7 +275,9 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { * @param event */ private onChannelMessage(event: MessageEvent): void { - this.logger.trace("NativeMessageHandler - onChannelMessage called."); + this.logger.trace( + "PlatformAuthExtensionHandler - onChannelMessage called." + ); const request = event.data; const resolver = this.resolvers.get(request.responseId); @@ -289,10 +294,10 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { } const response = request.body.response; this.logger.trace( - "NativeMessageHandler - Received response from browser extension" + "PlatformAuthExtensionHandler - Received response from browser extension" ); this.logger.tracePii( - `NativeMessageHandler - Received response from browser extension: ${JSON.stringify( + `PlatformAuthExtensionHandler - Received response from browser extension: ${JSON.stringify( response )}` ); @@ -329,7 +334,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { } else if (method === NativeExtensionMethod.HandshakeResponse) { if (!handshakeResolver) { this.logger.trace( - `NativeMessageHandler.onChannelMessage - resolver can't be found for request ${request.responseId}` + `PlatformAuthExtensionHandler.onChannelMessage - resolver can't be found for request ${request.responseId}` ); return; } @@ -342,7 +347,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { this.extensionId = request.extensionId; this.extensionVersion = request.body.version; this.logger.verbose( - `NativeMessageHandler - Received HandshakeResponse from extension: ${this.extensionId}` + `PlatformAuthExtensionHandler - Received HandshakeResponse from extension: ${this.extensionId}` ); this.handshakeEvent.end({ extensionInstalled: true, @@ -372,7 +377,9 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { * Validates native platform response before processing * @param response */ - validatePlatformBrokerResponse(response: object): PlatformBrokerResponse { + private validatePlatformBrokerResponse( + response: object + ): PlatformBrokerResponse { if ( response.hasOwnProperty("access_token") && response.hasOwnProperty("id_token") && @@ -405,4 +412,12 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { getExtensionVersion(): string | undefined { return this.extensionVersion; } + + getExtensionName(): string | undefined { + return this.getExtensionId() === NativeConstants.PREFERRED_EXTENSION_ID + ? "chrome" + : this.getExtensionId()?.length + ? "unknown" + : undefined; + } } diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 484c667ed5..55d5fbe31e 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -18,6 +18,7 @@ import { BrowserPerformanceClient } from "../../telemetry/BrowserPerformanceClie import { PlatformAuthExtensionHandler } from "./PlatformAuthExtensionHandler.js"; import { NativeConstants } from "../../utils/BrowserConstants.js"; import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js"; +import { PlatformAuthDOMHandler } from "./PlatformAuthDOMHandler.js"; /** * Checks if the platform broker is available in the current environment. @@ -48,45 +49,42 @@ export async function isPlatformBrokerAvailable( return false; } - // Check if DOM platform API is supported - - // @ts-ignore - if (window.navigator?.platformAuthentication) { - const supportedContracts = - // @ts-ignore - await window.navigator.platformAuthentication.getSupportedContracts( + try { + // Check if DOM platform API is supported first + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, NativeConstants.MICROSOFT_ENTRA_BROKERID ); - if (supportedContracts.includes("get-token-and-sign-out")) { - logger.trace("Platform auth available in DOM"); + if (platformAuthDOMHandler) { + logger.trace("Platform auth available via DOM, returning true"); return true; } - } - /* - * If DOM APIs are not available, check if browser extension is available. - * Platform authentication via DOM APIs is preferred over extension APIs. - */ - try { - const nativeExtensionProvider = + /* + * If DOM APIs are not available, check if browser extension is available. + * Platform authentication via DOM APIs is preferred over extension APIs. + */ + const platformAuthExtensionHandler = await PlatformAuthExtensionHandler.createProvider( logger, DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, performanceClient ); - if (nativeExtensionProvider) { + if (platformAuthExtensionHandler) { logger.trace( "Platform auth available via extension, returning true" ); return true; - } else { - logger.trace("Platform auth not available, returning false"); - return false; } } catch (e) { - logger.trace(e as string); + logger.trace("Platform auth not available", e as string); return false; } + + logger.trace("Platform auth not available, returning false"); + return false; } /** diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index e11535de38..12d10cc0c6 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -391,76 +391,36 @@ export class StandardController implements IController { } protected async setPlatformAuthProvider( + brokerId?: string, correlationId?: string ): Promise { - this.logger.trace("getPlatformAuthProvider called", correlationId); - - const domPlatformApiSupported = await this.checkDOMPlatformSupport( - correlationId - ); - - if (domPlatformApiSupported) { - this.platformAuthProvider = domPlatformApiSupported; - } else { - this.platformAuthProvider = - await PlatformAuthExtensionHandler.createProvider( - this.logger, - this.config.system.nativeBrokerHandshakeTimeout, - this.performanceClient - ); - - this.logger.trace( - "Platform API available via browser extension", - correlationId - ); - } - } - - protected async checkDOMPlatformSupport( - correlationId?: string, - brokerId?: string - ): Promise { - this.logger.trace("checkDOMPlatformSupport called", correlationId); - - if (!this.featureSupportConfig.enablePlatformBrokerDOMSupport) { - this.logger.trace( - "Platform DOM support is disabled, returning false.", - correlationId - ); - return; - } + this.logger.trace("setPlatformAuthProvider called", correlationId); if (!this.isBrowserEnvironment) { this.logger.trace("in non-browser environment, returning false."); return; } - // @ts-ignore - if (window.navigator?.platformAuthentication) { - const supportedContracts = - // @ts-ignore - await window.navigator.platformAuthentication.getSupportedContracts( - brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID - ); - if (supportedContracts.includes("get-token-and-sign-out")) { - this.logger.trace( - "Platform API available in DOM", - correlationId - ); - return new PlatformAuthDOMHandler( - this.logger, - this.performanceClient, - brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID, - correlationId - ); + try { + if (this.featureSupportConfig.enablePlatformBrokerDOMSupport) { + this.platformAuthProvider = + await PlatformAuthDOMHandler.createProvider( + this.logger, + this.performanceClient, + brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID + ); + } + if (!this.platformAuthProvider) { + this.platformAuthProvider = + await PlatformAuthExtensionHandler.createProvider( + this.logger, + this.config.system.nativeBrokerHandshakeTimeout, + this.performanceClient + ); } + } catch (e) { + this.logger.trace("Platform auth not available", e as string); } - - this.logger.trace( - "Platform DOM API not available, returning", - correlationId - ); - return; } // #region Redirect Flow diff --git a/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts b/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts index 388b2f6bcb..8a99387459 100644 --- a/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts @@ -126,16 +126,7 @@ export class PlatformAuthInteractionClient extends BaseInteractionClient { correlationId ); - const extensionName = - this.platformAuthProvider.getExtensionId() === - NativeConstants.PREFERRED_EXTENSION_ID - ? "chrome" - : this.platformAuthProvider.getExtensionId() === - NativeConstants.MICROSOFT_ENTRA_BROKERID - ? NativeConstants.MICROSOFT_ENTRA_BROKERID - : this.platformAuthProvider.getExtensionId()?.length - ? "unknown" - : undefined; + const extensionName = this.platformAuthProvider.getExtensionName(); this.skus = ServerTelemetryManager.makeExtraSkuString({ libraryName: BrowserConstants.MSAL_SKU, diff --git a/lib/msal-browser/src/utils/BrowserConstants.ts b/lib/msal-browser/src/utils/BrowserConstants.ts index c8c1ed6af2..6b3abf7d3e 100644 --- a/lib/msal-browser/src/utils/BrowserConstants.ts +++ b/lib/msal-browser/src/utils/BrowserConstants.ts @@ -46,6 +46,7 @@ export const NativeConstants = { PREFERRED_EXTENSION_ID: "ppnbnpeolgkicgegkbkbjmhlideopiji", MATS_TELEMETRY: "MATS", MICROSOFT_ENTRA_BROKERID: "MicrosoftEntra", + PLATFORM_DOM_APIS: "get-token-and-sign-out", PLATFORM_DOM_PROVIDER: "PlatformDOMHandler", PLATFORM_EXTENSION_PROVIDER: "NativeMessageHandler", }; From 9bcc2a88477cc66af307083838f1ab45b612d8fd Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 09:35:03 -0700 Subject: [PATCH 15/30] added support for enabling dom api feature through sessionStorage --- .../src/app/PublicClientApplication.ts | 24 ++++------------- lib/msal-browser/src/config/FeatureFlags.ts | 19 ------------- .../src/controllers/StandardController.ts | 8 +++--- lib/msal-browser/src/index.ts | 1 - .../operatingcontext/BaseOperatingContext.ts | 27 ++++++++----------- .../src/utils/BrowserConstants.ts | 2 ++ 6 files changed, 22 insertions(+), 59 deletions(-) delete mode 100644 lib/msal-browser/src/config/FeatureFlags.ts diff --git a/lib/msal-browser/src/app/PublicClientApplication.ts b/lib/msal-browser/src/app/PublicClientApplication.ts index 98205a27b2..e7aba6fd38 100644 --- a/lib/msal-browser/src/app/PublicClientApplication.ts +++ b/lib/msal-browser/src/app/PublicClientApplication.ts @@ -35,7 +35,6 @@ import { NestedAppAuthController } from "../controllers/NestedAppAuthController. import { NestedAppOperatingContext } from "../operatingcontext/NestedAppOperatingContext.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { EventType } from "../event/EventType.js"; -import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; /** * The PublicClientApplication class is the object exposed by the library to perform authentication and authorization functions in Single Page Applications @@ -50,17 +49,12 @@ export class PublicClientApplication implements IPublicClientApplication { * @param configuration {Configuration} */ public static async createPublicClientApplication( - configuration: Configuration, - featureConfig?: FeatureSupportConfiguration + configuration: Configuration ): Promise { const controller = await ControllerFactory.createV3Controller( configuration ); - const pca = new PublicClientApplication( - configuration, - featureConfig, - controller - ); + const pca = new PublicClientApplication(configuration, controller); return pca; } @@ -88,16 +82,10 @@ export class PublicClientApplication implements IPublicClientApplication { * @param featureConfig Optional parameter to explictly enable any feature support. * @param IController Optional parameter to explictly set the controller. (Will be removed when we remove public constructor) */ - public constructor( - configuration: Configuration, - featureConfig?: FeatureSupportConfiguration, - controller?: IController - ) { + public constructor(configuration: Configuration, controller?: IController) { this.controller = controller || - new StandardController( - new StandardOperatingContext(configuration, featureConfig) - ); + new StandardController(new StandardOperatingContext(configuration)); } /** @@ -452,8 +440,7 @@ export class PublicClientApplication implements IPublicClientApplication { * */ export async function createNestablePublicClientApplication( - configuration: Configuration, - featureConfig?: FeatureSupportConfiguration + configuration: Configuration ): Promise { const nestedAppAuth = new NestedAppOperatingContext(configuration); await nestedAppAuth.initialize(); @@ -462,7 +449,6 @@ export async function createNestablePublicClientApplication( const controller = new NestedAppAuthController(nestedAppAuth); const nestablePCA = new PublicClientApplication( configuration, - featureConfig, controller ); await nestablePCA.initialize(); diff --git a/lib/msal-browser/src/config/FeatureFlags.ts b/lib/msal-browser/src/config/FeatureFlags.ts deleted file mode 100644 index dc6697a234..0000000000 --- a/lib/msal-browser/src/config/FeatureFlags.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -// feature flag configuration for new features in MSAL.js -export type FeatureSupportConfiguration = { - enablePlatformBrokerDOMSupport?: boolean; -}; - -// populate user input or return default values -export function buildFeatureSupportConfiguration( - userInput?: FeatureSupportConfiguration -): FeatureSupportConfiguration { - return { - enablePlatformBrokerDOMSupport: - userInput?.enablePlatformBrokerDOMSupport || false, - }; -} diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 12d10cc0c6..a58cc20cc2 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -90,7 +90,6 @@ import { InitializeApplicationRequest } from "../request/InitializeApplicationRe import { generatePkceCodes } from "../crypto/PkceGenerator.js"; import { PlatformAuthDOMHandler } from "../broker/nativeBroker/PlatformAuthDOMHandler.js"; import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; -import { FeatureSupportConfiguration } from "../config/FeatureFlags.js"; import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; function getAccountType( @@ -144,7 +143,7 @@ export class StandardController implements IController { protected readonly config: BrowserConfiguration; // Feature support configuration - protected readonly featureSupportConfig: FeatureSupportConfiguration; + protected readonly enablePlatformBrokerDOMSupport: boolean; // Token cache implementation private tokenCache: TokenCache; @@ -216,7 +215,8 @@ export class StandardController implements IController { this.operatingContext.isBrowserEnvironment(); // Set the configuration. this.config = operatingContext.getConfig(); - this.featureSupportConfig = operatingContext.getFeatureSupportConfig(); + this.enablePlatformBrokerDOMSupport = + operatingContext.isDomEnabledForPlatformAuth(); this.initialized = false; // Initialize logger @@ -402,7 +402,7 @@ export class StandardController implements IController { } try { - if (this.featureSupportConfig.enablePlatformBrokerDOMSupport) { + if (this.enablePlatformBrokerDOMSupport) { this.platformAuthProvider = await PlatformAuthDOMHandler.createProvider( this.logger, diff --git a/lib/msal-browser/src/index.ts b/lib/msal-browser/src/index.ts index f3883845ce..8c605a473e 100644 --- a/lib/msal-browser/src/index.ts +++ b/lib/msal-browser/src/index.ts @@ -27,7 +27,6 @@ export { BrowserConfiguration, DEFAULT_IFRAME_TIMEOUT_MS, } from "./config/Configuration.js"; -export { FeatureSupportConfiguration } from "./config/FeatureFlags.js"; export { InteractionType, InteractionStatus, diff --git a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts index 670e855f62..6344fd2551 100644 --- a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts +++ b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts @@ -14,11 +14,8 @@ import { BrowserCacheLocation, LOG_LEVEL_CACHE_KEY, LOG_PII_CACHE_KEY, + PLATFORM_AUTH_DOM_SUPPORT, } from "../utils/BrowserConstants.js"; -import { - buildFeatureSupportConfiguration, - FeatureSupportConfiguration, -} from "../config/FeatureFlags.js"; /** * Base class for operating context @@ -32,7 +29,6 @@ export abstract class BaseOperatingContext { protected config: BrowserConfiguration; protected available: boolean; protected browserEnvironment: boolean; - protected featureSupportConfig: FeatureSupportConfiguration; protected static loggerCallback(level: LogLevel, message: string): void { switch (level) { @@ -59,10 +55,7 @@ export abstract class BaseOperatingContext { } } - constructor( - config: Configuration, - featureSupportConfig?: FeatureSupportConfiguration - ) { + constructor(config: Configuration) { /* * If loaded in an environment where window is not available, * set internal flag to false so that further requests fail. @@ -70,9 +63,6 @@ export abstract class BaseOperatingContext { */ this.browserEnvironment = typeof window !== "undefined"; this.config = buildConfiguration(config, this.browserEnvironment); - this.featureSupportConfig = - buildFeatureSupportConfiguration(featureSupportConfig); - let sessionStorage: Storage | undefined; try { sessionStorage = window[BrowserCacheLocation.SessionStorage]; @@ -132,11 +122,16 @@ export abstract class BaseOperatingContext { } /** - * Return MSAL config for enabled features - * @returns FeatureSupportConfiguration + * Returns true if the DOM API support for platform auth is enabled in session storage + * @returns boolean */ - getFeatureSupportConfig(): FeatureSupportConfiguration { - return this.featureSupportConfig; + isDomEnabledForPlatformAuth(): boolean { + try { + sessionStorage = window[BrowserCacheLocation.SessionStorage]; + // Mute errors if it's a non-browser environment or cookies are blocked. + } catch (e) {} + + return sessionStorage?.getItem(PLATFORM_AUTH_DOM_SUPPORT) === "true"; } /** diff --git a/lib/msal-browser/src/utils/BrowserConstants.ts b/lib/msal-browser/src/utils/BrowserConstants.ts index 6b3abf7d3e..ebc21a7211 100644 --- a/lib/msal-browser/src/utils/BrowserConstants.ts +++ b/lib/msal-browser/src/utils/BrowserConstants.ts @@ -252,3 +252,5 @@ export const LOG_LEVEL_CACHE_KEY = "msal.browser.log.level"; export const LOG_PII_CACHE_KEY = "msal.browser.log.pii"; export const BROWSER_PERF_ENABLED_KEY = "msal.browser.performance.enabled"; + +export const PLATFORM_AUTH_DOM_SUPPORT = "msal.browser.platform.auth.dom"; From 1a6541c27ebb6f76cf98a0e40d8557a1abad702b Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 09:44:50 -0700 Subject: [PATCH 16/30] updated sample with isPlatformBrokerAvailable usage --- .../VanillaJSTestApp2.0/app/wamBroker/authConfig.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js index 3714c6dd9b..602c16b197 100644 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js +++ b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js @@ -1,8 +1,16 @@ +// demo usage of isPlatformBrokerAvailable API +const isPlatformBrokerAvailable = msal.isPlatformBrokerAvailable().then((isAvailable) => { + console.log(`isNativeAvailable: ${isAvailable}`); + return isAvailable; +}).catch((error) => { + console.error("Error checking if platform broker is available:", error); +}); + // Config object to be passed to Msal on creation const msalConfig = { auth: { - clientId: "b5c2e510-4a17-4feb-b219-e55aa5b74144", - authority: "https://login.microsoftonline.com/common" + clientId: "591ddbcc-105b-42c5-89e6-c7638c4124d4", + authority: "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca" }, cache: { cacheLocation: "sessionStorage", // This configures where your cache will be stored From e3d06064d993cd4a85614f4abd46a63bb81ffeec Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 11:30:29 -0700 Subject: [PATCH 17/30] updating comment --- lib/msal-browser/src/app/PublicClientApplication.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/msal-browser/src/app/PublicClientApplication.ts b/lib/msal-browser/src/app/PublicClientApplication.ts index edf1572aaf..e479003029 100644 --- a/lib/msal-browser/src/app/PublicClientApplication.ts +++ b/lib/msal-browser/src/app/PublicClientApplication.ts @@ -80,7 +80,6 @@ export class PublicClientApplication implements IPublicClientApplication { * Full B2C functionality will be available in this library in future versions. * * @param configuration Object for the MSAL PublicClientApplication instance - * @param featureConfig Optional parameter to explictly enable any feature support. * @param IController Optional parameter to explictly set the controller. (Will be removed when we remove public constructor) */ public constructor(configuration: Configuration, controller?: IController) { From 94007c2c388226248e0846c5097fae6f2af3b375 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 11:31:53 -0700 Subject: [PATCH 18/30] Change files --- ...-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json diff --git a/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json b/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json new file mode 100644 index 0000000000..c5134cbf10 --- /dev/null +++ b/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Add support for new platform broker flow via DOM API", + "packageName": "@azure/msal-browser", + "email": "lalimasharda@microsoft.com", + "dependentChangeType": "patch" +} From 635dbbe6d6798be7fb764de8bc73eca5b8ec7d47 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 11:32:39 -0700 Subject: [PATCH 19/30] change file updates --- ...azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json b/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json index c5134cbf10..ea379c11b0 100644 --- a/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json +++ b/change/@azure-msal-browser-a202c777-7916-40aa-a0fe-81b7a800d1c7.json @@ -1,6 +1,6 @@ { "type": "minor", - "comment": "Add support for new platform broker flow via DOM API", + "comment": "Add support for new platform broker flow via DOM API #7632", "packageName": "@azure/msal-browser", "email": "lalimasharda@microsoft.com", "dependentChangeType": "patch" From 6e7443ce6852b5c8e04ad578bcaeae2ba4573615 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 13:29:38 -0700 Subject: [PATCH 20/30] hardcoding brokerId param --- .../src/broker/nativeBroker/PlatformAuthDOMHandler.ts | 10 ++++------ .../src/broker/nativeBroker/PlatformAuthProvider.ts | 3 +-- lib/msal-browser/src/controllers/StandardController.ts | 5 +---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index ab32621ebb..b4acf4adc2 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -34,12 +34,11 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { constructor( logger: Logger, performanceClient: IPerformanceClient, - brokerId?: string, correlationId?: string ) { this.logger = logger; this.performanceClient = performanceClient; - this.brokerId = brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID; + this.brokerId = NativeConstants.MICROSOFT_ENTRA_BROKERID; this.correlationId = correlationId || createNewGuid(); this.extensionVersion = ""; this.platformAuthType = NativeConstants.PLATFORM_DOM_PROVIDER; @@ -47,8 +46,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { static async createProvider( logger: Logger, - performanceClient: IPerformanceClient, - brokerId?: string + performanceClient: IPerformanceClient ): Promise { logger.trace("PlatformAuthDOMHandler: createProvider called"); @@ -57,7 +55,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { const supportedContracts = // @ts-ignore await window.navigator.platformAuthentication.getSupportedContracts( - brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID + NativeConstants.MICROSOFT_ENTRA_BROKERID ); if ( supportedContracts?.includes(NativeConstants.PLATFORM_DOM_APIS) @@ -66,7 +64,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { return new PlatformAuthDOMHandler( logger, performanceClient, - brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID + NativeConstants.MICROSOFT_ENTRA_BROKERID ); } } diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 55d5fbe31e..c1a6fbe018 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -54,8 +54,7 @@ export async function isPlatformBrokerAvailable( const platformAuthDOMHandler = await PlatformAuthDOMHandler.createProvider( logger, - performanceClient, - NativeConstants.MICROSOFT_ENTRA_BROKERID + performanceClient ); if (platformAuthDOMHandler) { logger.trace("Platform auth available via DOM, returning true"); diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 71fe63c053..6b6c744986 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -45,7 +45,6 @@ import { DEFAULT_REQUEST, BrowserConstants, iFrameRenewalPolicies, - NativeConstants, INTERACTION_TYPE, } from "../utils/BrowserConstants.js"; import * as BrowserUtils from "../utils/BrowserUtils.js"; @@ -402,7 +401,6 @@ export class StandardController implements IController { } protected async setPlatformAuthProvider( - brokerId?: string, correlationId?: string ): Promise { this.logger.trace("setPlatformAuthProvider called", correlationId); @@ -417,8 +415,7 @@ export class StandardController implements IController { this.platformAuthProvider = await PlatformAuthDOMHandler.createProvider( this.logger, - this.performanceClient, - brokerId || NativeConstants.MICROSOFT_ENTRA_BROKERID + this.performanceClient ); } if (!this.platformAuthProvider) { From 5ad75468e4d47fcf2ff0d941f89f2b909bbc37a2 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Tue, 6 May 2025 15:21:11 -0700 Subject: [PATCH 21/30] fixing isDomEnabledForPlatformAuth --- .../src/operatingcontext/BaseOperatingContext.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts index 6344fd2551..3222c91fb5 100644 --- a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts +++ b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts @@ -129,9 +129,12 @@ export abstract class BaseOperatingContext { try { sessionStorage = window[BrowserCacheLocation.SessionStorage]; // Mute errors if it's a non-browser environment or cookies are blocked. - } catch (e) {} - - return sessionStorage?.getItem(PLATFORM_AUTH_DOM_SUPPORT) === "true"; + return ( + sessionStorage?.getItem(PLATFORM_AUTH_DOM_SUPPORT) === "true" + ); + } catch (e) { + return false; + } } /** From 7643939f16d5732df11f8b881f56321672fdb09f Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 7 May 2025 15:59:16 -0700 Subject: [PATCH 22/30] addressed commits and fixed unit tests --- .../nativeBroker/PlatformAuthDOMHandler.ts | 29 ++- .../PlatformAuthExtensionHandler.ts | 20 +- .../nativeBroker/PlatformAuthProvider.ts | 100 +++++---- .../src/controllers/StandardController.ts | 50 +---- .../PlatformAuthInteractionClient.ts | 4 +- .../operatingcontext/BaseOperatingContext.ts | 17 -- .../src/utils/BrowserConstants.ts | 3 +- .../test/app/PublicClientApplication.spec.ts | 49 +++-- ...s => PlatformAuthExtensionHandler.spec.ts} | 95 ++++---- ... => PlatformAuthInteractionClient.spec.ts} | 206 ++++++++++-------- 10 files changed, 300 insertions(+), 273 deletions(-) rename lib/msal-browser/test/broker/{NativeMessageHandler.spec.ts => PlatformAuthExtensionHandler.spec.ts} (88%) rename lib/msal-browser/test/interaction_client/{NativeInteractionClient.spec.ts => PlatformAuthInteractionClient.spec.ts} (89%) diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index b4acf4adc2..5cad48d91e 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -14,8 +14,7 @@ import { PlatformBrokerRequest, PlatformDOMTokenRequest, } from "./PlatformBrokerRequest.js"; -import { createNewGuid } from "../../crypto/BrowserCrypto.js"; -import { NativeConstants } from "../../utils/BrowserConstants.js"; +import { PlatformAuthConstants } from "../../utils/BrowserConstants.js"; import { PlatformBrokerResponse, PlatformDOMTokenResponse, @@ -34,19 +33,20 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { constructor( logger: Logger, performanceClient: IPerformanceClient, - correlationId?: string + correlationId: string ) { this.logger = logger; this.performanceClient = performanceClient; - this.brokerId = NativeConstants.MICROSOFT_ENTRA_BROKERID; - this.correlationId = correlationId || createNewGuid(); + this.brokerId = PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID; + this.correlationId = correlationId; this.extensionVersion = ""; - this.platformAuthType = NativeConstants.PLATFORM_DOM_PROVIDER; + this.platformAuthType = PlatformAuthConstants.PLATFORM_DOM_PROVIDER; } static async createProvider( logger: Logger, - performanceClient: IPerformanceClient + performanceClient: IPerformanceClient, + correlationId: string ): Promise { logger.trace("PlatformAuthDOMHandler: createProvider called"); @@ -55,16 +55,18 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { const supportedContracts = // @ts-ignore await window.navigator.platformAuthentication.getSupportedContracts( - NativeConstants.MICROSOFT_ENTRA_BROKERID + PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID ); if ( - supportedContracts?.includes(NativeConstants.PLATFORM_DOM_APIS) + supportedContracts?.includes( + PlatformAuthConstants.PLATFORM_DOM_APIS + ) ) { logger.trace("Platform auth api available in DOM"); return new PlatformAuthDOMHandler( logger, performanceClient, - NativeConstants.MICROSOFT_ENTRA_BROKERID + correlationId ); } } @@ -79,15 +81,12 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { return this.brokerId; } - /** - * Gets the version of the browser this handler is communicating with - */ getExtensionVersion(): string | undefined { - return ""; + return this.extensionVersion; } getExtensionName(): string | undefined { - return this.brokerId; + return PlatformAuthConstants.DOM_API_NAME; } /** diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts index 9d6cb0cfea..9fcf899464 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts @@ -4,7 +4,7 @@ */ import { - NativeConstants, + PlatformAuthConstants, NativeExtensionMethod, } from "../../utils/BrowserConstants.js"; import { @@ -68,7 +68,8 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { this.handshakeEvent = performanceClient.startMeasurement( PerformanceEvents.NativeMessageHandlerHandshake ); - this.platformAuthType = NativeConstants.PLATFORM_EXTENSION_PROVIDER; + this.platformAuthType = + PlatformAuthConstants.PLATFORM_EXTENSION_PROVIDER; } /** @@ -80,16 +81,14 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { ): Promise { this.logger.trace("PlatformAuthExtensionHandler - sendMessage called."); - const { ...nativeTokenRequest } = request; - // fall back to native calls const messageBody: NativeExtensionRequestBody = { method: NativeExtensionMethod.GetToken, - request: nativeTokenRequest, + request: request, }; const req: NativeExtensionRequest = { - channel: NativeConstants.CHANNEL_ID, + channel: PlatformAuthConstants.CHANNEL_ID, extensionId: this.extensionId, responseId: createNewGuid(), body: messageBody, @@ -134,7 +133,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { logger, handshakeTimeoutMs, performanceClient, - NativeConstants.PREFERRED_EXTENSION_ID + PlatformAuthConstants.PREFERRED_EXTENSION_ID ); await preferredProvider.sendHandshakeRequest(); return preferredProvider; @@ -161,7 +160,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first const req: NativeExtensionRequest = { - channel: NativeConstants.CHANNEL_ID, + channel: PlatformAuthConstants.CHANNEL_ID, extensionId: this.extensionId, responseId: createNewGuid(), body: { @@ -224,7 +223,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { if ( !request.channel || - request.channel !== NativeConstants.CHANNEL_ID + request.channel !== PlatformAuthConstants.CHANNEL_ID ) { return; } @@ -414,7 +413,8 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { } getExtensionName(): string | undefined { - return this.getExtensionId() === NativeConstants.PREFERRED_EXTENSION_ID + return this.getExtensionId() === + PlatformAuthConstants.PREFERRED_EXTENSION_ID ? "chrome" : this.getExtensionId()?.length ? "unknown" diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index c1a6fbe018..16f97d2c33 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -8,17 +8,21 @@ import { IPerformanceClient, Logger, AuthenticationScheme, + StubPerformanceClient, } from "@azure/msal-common/browser"; import { name, version } from "../../packageMetadata.js"; import { BrowserConfiguration, DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, } from "../../config/Configuration.js"; -import { BrowserPerformanceClient } from "../../telemetry/BrowserPerformanceClient.js"; import { PlatformAuthExtensionHandler } from "./PlatformAuthExtensionHandler.js"; -import { NativeConstants } from "../../utils/BrowserConstants.js"; import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js"; import { PlatformAuthDOMHandler } from "./PlatformAuthDOMHandler.js"; +import { createNewGuid } from "../../crypto/BrowserCrypto.js"; +import { + BrowserCacheLocation, + PLATFORM_AUTH_DOM_SUPPORT, +} from "../../utils/BrowserConstants.js"; /** * Checks if the platform broker is available in the current environment. @@ -28,62 +32,82 @@ import { PlatformAuthDOMHandler } from "./PlatformAuthDOMHandler.js"; */ export async function isPlatformBrokerAvailable( loggerOptions?: LoggerOptions, - perfClient?: IPerformanceClient + perfClient?: IPerformanceClient, + correlationId?: string ): Promise { const logger = new Logger(loggerOptions || {}, name, version); logger.trace("isPlatformBrokerAvailable called"); - const defaultPerformanceClientConfig = { - auth: { - clientId: "", - }, - }; - - const performanceClient = - perfClient || - new BrowserPerformanceClient(defaultPerformanceClientConfig); + const performanceClient = perfClient || new StubPerformanceClient(); if (!window) { logger.trace("Non DOM environment detected, returning false"); return false; } + return !!getPlatformAuthProvider( + logger, + performanceClient, + correlationId || createNewGuid() + ); +} + +export async function getPlatformAuthProvider( + logger: Logger, + performanceClient: IPerformanceClient, + correlationId: string, + nativeBrokerHandshakeTimeout?: number +): Promise { + logger.trace("getPlatformAuthProvider called", correlationId); + + const enablePlatformBrokerDOMSupport = isDomEnabledForPlatformAuth(); + + logger.trace( + "Platform auth available via DOM API: " + enablePlatformBrokerDOMSupport + ); + let platformAuthProvider: IPlatformAuthHandler | undefined; try { - // Check if DOM platform API is supported first - const platformAuthDOMHandler = - await PlatformAuthDOMHandler.createProvider( + if (enablePlatformBrokerDOMSupport) { + // Check if DOM platform API is supported first + platformAuthProvider = await PlatformAuthDOMHandler.createProvider( logger, - performanceClient + performanceClient, + correlationId ); - if (platformAuthDOMHandler) { - logger.trace("Platform auth available via DOM, returning true"); - return true; } - - /* - * If DOM APIs are not available, check if browser extension is available. - * Platform authentication via DOM APIs is preferred over extension APIs. - */ - const platformAuthExtensionHandler = - await PlatformAuthExtensionHandler.createProvider( - logger, - DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, - performanceClient - ); - if (platformAuthExtensionHandler) { - logger.trace( - "Platform auth available via extension, returning true" - ); - return true; + if (!platformAuthProvider) { + /* + * If DOM APIs are not available, check if browser extension is available. + * Platform authentication via DOM APIs is preferred over extension APIs. + */ + platformAuthProvider = + await PlatformAuthExtensionHandler.createProvider( + logger, + nativeBrokerHandshakeTimeout || + DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS, + performanceClient + ); } } catch (e) { logger.trace("Platform auth not available", e as string); - return false; } + return platformAuthProvider; +} - logger.trace("Platform auth not available, returning false"); - return false; +/** + * Returns true if the DOM API support for platform auth is enabled in session storage + * @returns boolean + */ +export function isDomEnabledForPlatformAuth(): boolean { + let sessionStorage: Storage | undefined; + try { + sessionStorage = window[BrowserCacheLocation.SessionStorage]; + // Mute errors if it's a non-browser environment or cookies are blocked. + return sessionStorage?.getItem(PLATFORM_AUTH_DOM_SUPPORT) === "true"; + } catch (e) { + return false; + } } /** diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 6b6c744986..6b4db400ad 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -64,7 +64,6 @@ import { SilentRefreshClient } from "../interaction_client/SilentRefreshClient.j import { TokenCache } from "../cache/TokenCache.js"; import { ITokenCache } from "../cache/ITokenCache.js"; import { PlatformAuthInteractionClient } from "../interaction_client/PlatformAuthInteractionClient.js"; -import { PlatformAuthExtensionHandler } from "../broker/nativeBroker/PlatformAuthExtensionHandler.js"; import { SilentRequest } from "../request/SilentRequest.js"; import { NativeAuthError, @@ -87,8 +86,10 @@ import { createNewGuid } from "../crypto/BrowserCrypto.js"; import { initializeSilentRequest } from "../request/RequestHelpers.js"; import { InitializeApplicationRequest } from "../request/InitializeApplicationRequest.js"; import { generatePkceCodes } from "../crypto/PkceGenerator.js"; -import { PlatformAuthDOMHandler } from "../broker/nativeBroker/PlatformAuthDOMHandler.js"; -import { isBrokerAvailable } from "../broker/nativeBroker/PlatformAuthProvider.js"; +import { + getPlatformAuthProvider, + isBrokerAvailable, +} from "../broker/nativeBroker/PlatformAuthProvider.js"; import { IPlatformAuthHandler } from "../broker/nativeBroker/IPlatformAuthHandler.js"; import { collectInstanceStats } from "../utils/MsalFrameStatsUtils.js"; @@ -142,9 +143,6 @@ export class StandardController implements IController { // Input configuration by developer/user protected readonly config: BrowserConfiguration; - // Feature support configuration - protected readonly enablePlatformBrokerDOMSupport: boolean; - // Token cache implementation private tokenCache: TokenCache; @@ -215,8 +213,6 @@ export class StandardController implements IController { this.operatingContext.isBrowserEnvironment(); // Set the configuration. this.config = operatingContext.getConfig(); - this.enablePlatformBrokerDOMSupport = - operatingContext.isDomEnabledForPlatformAuth(); this.initialized = false; // Initialize logger @@ -368,7 +364,12 @@ export class StandardController implements IController { if (allowPlatformBroker) { try { // check if platform authentication is available via DOM or browser extension and create relevant handlers - await this.setPlatformAuthProvider(); + this.platformAuthProvider = await getPlatformAuthProvider( + this.logger, + this.performanceClient, + initCorrelationId, + this.config.system.nativeBrokerHandshakeTimeout + ); } catch (e) { this.logger.verbose(e as string); } @@ -400,37 +401,6 @@ export class StandardController implements IController { }); } - protected async setPlatformAuthProvider( - correlationId?: string - ): Promise { - this.logger.trace("setPlatformAuthProvider called", correlationId); - - if (!this.isBrowserEnvironment) { - this.logger.trace("in non-browser environment, returning false."); - return; - } - - try { - if (this.enablePlatformBrokerDOMSupport) { - this.platformAuthProvider = - await PlatformAuthDOMHandler.createProvider( - this.logger, - this.performanceClient - ); - } - if (!this.platformAuthProvider) { - this.platformAuthProvider = - await PlatformAuthExtensionHandler.createProvider( - this.logger, - this.config.system.nativeBrokerHandshakeTimeout, - this.performanceClient - ); - } - } catch (e) { - this.logger.trace("Platform auth not available", e as string); - } - } - // #region Redirect Flow /** diff --git a/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts b/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts index 8a99387459..40ded8e005 100644 --- a/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/PlatformAuthInteractionClient.ts @@ -46,7 +46,7 @@ import { SsoSilentRequest } from "../request/SsoSilentRequest.js"; import { ApiId, TemporaryCacheKeys, - NativeConstants, + PlatformAuthConstants, BrowserConstants, CacheLookupPolicy, } from "../utils/BrowserConstants.js"; @@ -924,7 +924,7 @@ export class PlatformAuthInteractionClient extends BaseInteractionClient { validatedRequest.extraParameters = validatedRequest.extraParameters || {}; validatedRequest.extraParameters.telemetry = - NativeConstants.MATS_TELEMETRY; + PlatformAuthConstants.MATS_TELEMETRY; if (request.authenticationScheme === AuthenticationScheme.POP) { // add POP request type diff --git a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts index 3222c91fb5..c615265c24 100644 --- a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts +++ b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts @@ -14,7 +14,6 @@ import { BrowserCacheLocation, LOG_LEVEL_CACHE_KEY, LOG_PII_CACHE_KEY, - PLATFORM_AUTH_DOM_SUPPORT, } from "../utils/BrowserConstants.js"; /** @@ -121,22 +120,6 @@ export abstract class BaseOperatingContext { return this.config; } - /** - * Returns true if the DOM API support for platform auth is enabled in session storage - * @returns boolean - */ - isDomEnabledForPlatformAuth(): boolean { - try { - sessionStorage = window[BrowserCacheLocation.SessionStorage]; - // Mute errors if it's a non-browser environment or cookies are blocked. - return ( - sessionStorage?.getItem(PLATFORM_AUTH_DOM_SUPPORT) === "true" - ); - } catch (e) { - return false; - } - } - /** * Returns the MSAL Logger * @returns Logger diff --git a/lib/msal-browser/src/utils/BrowserConstants.ts b/lib/msal-browser/src/utils/BrowserConstants.ts index ebc21a7211..c5c6b72d45 100644 --- a/lib/msal-browser/src/utils/BrowserConstants.ts +++ b/lib/msal-browser/src/utils/BrowserConstants.ts @@ -41,11 +41,12 @@ export const BrowserConstants = { MSAL_SKU: "msal.js.browser", }; -export const NativeConstants = { +export const PlatformAuthConstants = { CHANNEL_ID: "53ee284d-920a-4b59-9d30-a60315b26836", PREFERRED_EXTENSION_ID: "ppnbnpeolgkicgegkbkbjmhlideopiji", MATS_TELEMETRY: "MATS", MICROSOFT_ENTRA_BROKERID: "MicrosoftEntra", + DOM_API_NAME: "DOM API", PLATFORM_DOM_APIS: "get-token-and-sign-out", PLATFORM_DOM_PROVIDER: "PlatformDOMHandler", PLATFORM_EXTENSION_PROVIDER: "NativeMessageHandler", diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 38ce9c25f7..8ff74da89d 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -60,7 +60,7 @@ import { BrowserConstants, CacheLookupPolicy, InteractionType, - NativeConstants, + PlatformAuthConstants, TemporaryCacheKeys, WrapperSKU, } from "../../src/utils/BrowserConstants.js"; @@ -96,6 +96,7 @@ import { import { SilentAuthCodeClient } from "../../src/interaction_client/SilentAuthCodeClient.js"; import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; +import * as PlatformAuthProvider from "../../src/broker/nativeBroker/PlatformAuthProvider.js"; import { PlatformAuthInteractionClient } from "../../src/interaction_client/PlatformAuthInteractionClient.js"; import { PlatformBrokerRequest } from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; import { NativeAuthError } from "../../src/error/NativeAuthError.js"; @@ -116,6 +117,7 @@ import { TestTimeUtils, } from "msal-test-utils"; import { INTERACTION_TYPE } from "../../src/utils/BrowserConstants.js"; +import { BaseOperatingContext } from "../../src/operatingcontext/BaseOperatingContext.js"; const cacheConfig = { temporaryCacheLocation: BrowserCacheLocation.SessionStorage, @@ -299,8 +301,9 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { event.stopImmediatePropagation(); const request = event.data; const req = { - channel: NativeConstants.CHANNEL_ID, - extensionId: NativeConstants.PREFERRED_EXTENSION_ID, + channel: PlatformAuthConstants.CHANNEL_ID, + extensionId: + PlatformAuthConstants.PREFERRED_EXTENSION_ID, responseId: request.responseId, body: { method: "HandshakeResponse", @@ -388,8 +391,9 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { event.stopImmediatePropagation(); const request = event.data; const req = { - channel: NativeConstants.CHANNEL_ID, - extensionId: NativeConstants.PREFERRED_EXTENSION_ID, + channel: PlatformAuthConstants.CHANNEL_ID, + extensionId: + PlatformAuthConstants.PREFERRED_EXTENSION_ID, responseId: request.responseId, body: { method: "HandshakeResponse", @@ -456,6 +460,13 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { allowPlatformBroker: true, }, }; + + jest.spyOn( + PlatformAuthProvider, + "isDomEnabledForPlatformAuth" + ).mockImplementation(() => { + return false; + }); pca = new PublicClientApplication(config); const createProviderSpy = stubProvider(config); @@ -468,7 +479,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(createProviderSpy).toHaveBeenCalled(); // @ts-ignore - expect(pca.nativeExtensionProvider).toBeInstanceOf( + expect(pca.platformAuthProvider).toBeInstanceOf( PlatformAuthExtensionHandler ); }); @@ -493,7 +504,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(createProviderSpy).toHaveBeenCalledTimes(0); // @ts-ignore - expect(pca.nativeExtensionProvider).toBeUndefined(); + expect(pca.platformAuthProvider).toBeUndefined(); }); it("catches error if extension provider fails to initialize", async () => { @@ -515,7 +526,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(createProviderSpy).toHaveBeenCalled(); // @ts-ignore - expect(pca.nativeExtensionProvider).toBeUndefined(); + expect(pca.platformAuthProvider).toBeUndefined(); }); it("reports telemetry event using provided correlation id", (done) => { @@ -964,7 +975,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { //@ts-ignore pca.controller.browserStorage.setInteractionInProgress(true); - const nativeRequest: NativeTokenRequest = { + const nativeRequest: PlatformBrokerRequest = { authority: TEST_CONFIG.validAuthority, clientId: TEST_CONFIG.MSAL_CLIENT_ID, scope: TEST_CONFIG.DEFAULT_SCOPES.join(" "), @@ -6162,7 +6173,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(silentIframeSpy).toHaveBeenCalledTimes(0); }); - it("Calls SilentCacheClient.acquireToken, and calls NativeInteractionClient.acquireToken when CacheLookupPolicy is set to AccessToken", async () => { + it("Calls SilentCacheClient.acquireToken, and calls PlatformAuthInteractionClient.acquireToken when CacheLookupPolicy is set to AccessToken", async () => { const silentCacheSpy: jest.SpyInstance = jest .spyOn(SilentCacheClient.prototype, "acquireToken") .mockRejectedValue(refreshRequiredCacheError); @@ -6173,11 +6184,8 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { .spyOn(SilentIframeClient.prototype, "acquireToken") .mockImplementation(); - const isPlatformBrokerAvailableSpy = jest - .spyOn( - PlatformAuthExtensionHandler, - "isPlatformBrokerAvailable" - ) + const isBrokerAvailableSpy = jest + .spyOn(PlatformAuthProvider, "isBrokerAvailable") .mockReturnValue(true); const nativeAcquireTokenSpy: jest.SpyInstance = jest .spyOn( @@ -6207,7 +6215,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(nativeAcquireTokenSpy).toHaveBeenCalledTimes(0); nativeAcquireTokenSpy.mockRestore(); - isPlatformBrokerAvailableSpy.mockRestore(); + isBrokerAvailableSpy.mockRestore(); }); it("Calls SilentRefreshClient.acquireToken, and does not call SilentCacheClient.acquireToken or SilentIframeClient.acquireToken if refresh token is expired when CacheLookupPolicy is set to RefreshToken", async () => { @@ -6252,11 +6260,8 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { const cacheAccount = testAccount; cacheAccount.nativeAccountId = "nativeAccountId"; - const isPlatformBrokerAvailableSpy = jest - .spyOn( - PlatformAuthExtensionHandler, - "isPlatformBrokerAvailable" - ) + const isBrokerAvailableSpy = jest + .spyOn(PlatformAuthProvider, "isBrokerAvailable") .mockReturnValue(true); testAccount.nativeAccountId = "nativeAccountId"; @@ -6279,7 +6284,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(silentIframeSpy).toHaveBeenCalledTimes(0); expect(nativeAcquireTokenSpy).toHaveBeenCalledTimes(0); nativeAcquireTokenSpy.mockRestore(); - isPlatformBrokerAvailableSpy.mockRestore(); + isBrokerAvailableSpy.mockRestore(); }); it("Calls SilentRefreshClient.acquireToken, and does not call SilentCacheClient.acquireToken or SilentIframeClient.acquireToken if refresh token is expired when CacheLookupPolicy is set to RefreshToken", async () => { diff --git a/lib/msal-browser/test/broker/NativeMessageHandler.spec.ts b/lib/msal-browser/test/broker/PlatformAuthExtensionHandler.spec.ts similarity index 88% rename from lib/msal-browser/test/broker/NativeMessageHandler.spec.ts rename to lib/msal-browser/test/broker/PlatformAuthExtensionHandler.spec.ts index 6ce75bea59..ba54c4d7ca 100644 --- a/lib/msal-browser/test/broker/NativeMessageHandler.spec.ts +++ b/lib/msal-browser/test/broker/PlatformAuthExtensionHandler.spec.ts @@ -15,10 +15,23 @@ import { NativeExtensionMethod } from "../../src/utils/BrowserConstants.js"; import { NativeAuthError } from "../../src/error/NativeAuthError.js"; import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; import { CryptoOps } from "../../src/crypto/CryptoOps.js"; +import { mock } from "node:test"; +import { PlatformBrokerRequest } from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; +import { TEST_CONFIG, TEST_URIS } from "../utils/StringConstants.js"; let performanceClient: IPerformanceClient; -describe("NativeMessageHandler Tests", () => { +const TEST_REQUEST: PlatformBrokerRequest = { + accountId: "test-account-id", + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + authority: TEST_CONFIG.validAuthority, + redirectUri: TEST_URIS.TEST_REDIR_URI, + scope: "User.Read", + correlationId: "test-correlation-id", + windowTitleSubstring: "", +}; + +describe("PlatformAuthExtensionHandler Tests", () => { let postMessageSpy: jest.SpyInstance; let mcPort: MessagePort; let cryptoInterface: CryptoOps; @@ -239,11 +252,21 @@ describe("NativeMessageHandler Tests", () => { describe("sendMessage", () => { it("Sends message to WAM extension", async () => { + const testWAMResponse = { + access_token: "test-access-token", + id_token: "test-id-token", + client_info: "test-client-info", + account: { + id: "test-account-id", + properties: {}, + userName: "test-user-name", + }, + scope: "read openid", + expires_in: "3600", + }; const testResponse = { status: "Success", - result: { - accessToken: "test-access-token", - }, + result: testWAMResponse, }; const eventHandler = function (event: MessageEvent) { event.stopImmediatePropagation(); @@ -291,9 +314,7 @@ describe("NativeMessageHandler Tests", () => { PlatformAuthExtensionHandler ); - const response = await wamMessageHandler.sendMessage({ - method: NativeExtensionMethod.GetToken, - }); + const response = await wamMessageHandler.sendMessage(TEST_REQUEST); expect(response).toEqual(testResponse.result); window.removeEventListener("message", eventHandler, true); @@ -347,16 +368,14 @@ describe("NativeMessageHandler Tests", () => { performanceClient ) .then((wamMessageHandler) => { - wamMessageHandler - .sendMessage({ method: NativeExtensionMethod.GetToken }) - .catch((e) => { - expect(e).toBeInstanceOf(NativeAuthError); - expect(e.errorCode).toEqual(testResponse.code); - expect(e.errorMessage).toEqual( - testResponse.description - ); - done(); - }); + wamMessageHandler.sendMessage(TEST_REQUEST).catch((e) => { + expect(e).toBeInstanceOf(NativeAuthError); + expect(e.errorCode).toEqual(testResponse.code); + expect(e.errorMessage).toEqual( + testResponse.description + ); + done(); + }); }) .finally(() => { window.removeEventListener("message", eventHandler, true); @@ -413,18 +432,14 @@ describe("NativeMessageHandler Tests", () => { performanceClient ) .then((wamMessageHandler) => { - wamMessageHandler - .sendMessage({ method: NativeExtensionMethod.GetToken }) - .catch((e) => { - expect(e).toBeInstanceOf(NativeAuthError); - expect(e.errorCode).toEqual( - testResponse.result.code - ); - expect(e.errorMessage).toEqual( - testResponse.result.description - ); - done(); - }); + wamMessageHandler.sendMessage(TEST_REQUEST).catch((e) => { + expect(e).toBeInstanceOf(NativeAuthError); + expect(e.errorCode).toEqual(testResponse.result.code); + expect(e.errorMessage).toEqual( + testResponse.result.description + ); + done(); + }); }) .finally(() => { window.removeEventListener("message", eventHandler, true); @@ -477,18 +492,16 @@ describe("NativeMessageHandler Tests", () => { performanceClient ) .then((wamMessageHandler) => { - wamMessageHandler - .sendMessage({ method: NativeExtensionMethod.GetToken }) - .catch((e) => { - expect(e).toBeInstanceOf(AuthError); - expect(e.errorCode).toEqual( - AuthErrorMessage.unexpectedError.code - ); - expect(e.errorMessage).toContain( - AuthErrorMessage.unexpectedError.desc - ); - done(); - }); + wamMessageHandler.sendMessage(TEST_REQUEST).catch((e) => { + expect(e).toBeInstanceOf(AuthError); + expect(e.errorCode).toEqual( + AuthErrorMessage.unexpectedError.code + ); + expect(e.errorMessage).toContain( + AuthErrorMessage.unexpectedError.desc + ); + done(); + }); }) .finally(() => { window.removeEventListener("message", eventHandler, true); diff --git a/lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts b/lib/msal-browser/test/interaction_client/PlatformAuthInteractionClient.spec.ts similarity index 89% rename from lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts rename to lib/msal-browser/test/interaction_client/PlatformAuthInteractionClient.spec.ts index c9e325e376..9d4d33a0ec 100644 --- a/lib/msal-browser/test/interaction_client/NativeInteractionClient.spec.ts +++ b/lib/msal-browser/test/interaction_client/PlatformAuthInteractionClient.spec.ts @@ -39,7 +39,10 @@ import { NativeAuthErrorCodes, NativeAuthErrorMessages, } from "../../src/error/NativeAuthError.js"; -import { NativeExtensionRequestBody } from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; +import { + NativeExtensionRequestBody, + PlatformBrokerRequest, +} from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; import { BrowserCacheManager } from "../../src/cache/BrowserCacheManager.js"; import { @@ -52,8 +55,9 @@ import { buildAccountFromIdTokenClaims, buildIdToken } from "msal-test-utils"; import { version } from "../../src/packageMetadata.js"; import { BrowserConstants } from "../../src/utils/BrowserConstants.js"; import * as NativeStatusCodes from "../../src/broker/nativeBroker/NativeStatusCodes.js"; +import { PlatformBrokerResponse } from "../../src/broker/nativeBroker/PlatformBrokerResponse.js"; -const MOCK_WAM_RESPONSE = { +const MOCK_WAM_RESPONSE: PlatformBrokerResponse = { access_token: TEST_TOKENS.ACCESS_TOKEN, id_token: TEST_TOKENS.IDTOKEN_V2, scope: "User.Read", @@ -61,20 +65,26 @@ const MOCK_WAM_RESPONSE = { client_info: TEST_DATA_CLIENT_INFO.TEST_RAW_CLIENT_INFO, account: { id: "nativeAccountId", + properties: {}, + userName: "test_username", }, properties: {}, + state: "", }; -const MOCK_WAM_RESPONSE_STRING_EXPIRES_IN = { +const MOCK_WAM_RESPONSE_STRING_EXPIRES_IN: PlatformBrokerResponse = { access_token: TEST_TOKENS.ACCESS_TOKEN, id_token: TEST_TOKENS.IDTOKEN_V2, scope: "User.Read", - expires_in: "3600", + expires_in: 3600, client_info: TEST_DATA_CLIENT_INFO.TEST_RAW_CLIENT_INFO, account: { id: "nativeAccountId", + properties: {}, + userName: "test_username", }, properties: {}, + state: "", }; const testAccountEntity: AccountEntity = buildAccountFromIdTokenClaims( @@ -109,7 +119,7 @@ const testAccessTokenEntity: AccessTokenEntity = { cachedAt: `${TimeUtils.nowSeconds()}`, }; -describe("NativeInteractionClient Tests", () => { +describe("PlatformAuthInteractionClient Tests", () => { let pca: PublicClientApplication; let nativeInteractionClient: PlatformAuthInteractionClient; @@ -242,7 +252,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); const response = await nativeInteractionClient.acquireToken({ @@ -266,7 +276,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE_STRING_EXPIRES_IN); }); const response = await nativeInteractionClient.acquireToken({ @@ -329,7 +339,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); const response = await nativeInteractionClient.acquireToken({ @@ -354,7 +364,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); const response = await nativeInteractionClient.acquireToken({ @@ -379,7 +389,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); const response = await nativeInteractionClient.acquireToken({ @@ -401,16 +411,22 @@ describe("NativeInteractionClient Tests", () => { }); it("does not throw account switch error when homeaccountid is same", (done) => { - const mockWamResponse = { + const raw_client_info = + "eyJ1aWQiOiAiMDAwMDAwMDAtMDAwMC0wMDAwLTY2ZjMtMzMzMmVjYTdlYTgxIiwgInV0aWQiOiIzMzM4MDQwZC02YzY3LTRjNWItYjExMi0zNmEzMDRiNjZkYWQifQ=="; + + const mockWamResponse: PlatformBrokerResponse = { access_token: TEST_TOKENS.ACCESS_TOKEN, - id_token: TEST_TOKENS.IDTOKEN_V2, + id_token: TEST_TOKENS.IDTOKEN_V2_ALT, scope: "User.Read", expires_in: 3600, - client_info: TEST_DATA_CLIENT_INFO.TEST_RAW_CLIENT_INFO, + client_info: raw_client_info, account: { id: "different-nativeAccountId", + properties: {}, + userName: "test_username", }, properties: {}, + state: "", }; jest.spyOn( @@ -421,7 +437,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(mockWamResponse); }); nativeInteractionClient @@ -447,7 +463,7 @@ describe("NativeInteractionClient Tests", () => { const raw_client_info = "eyJ1aWQiOiAiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIiwgInV0aWQiOiI3MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcifQ=="; - const mockWamResponse = { + const mockWamResponse: PlatformBrokerResponse = { access_token: TEST_TOKENS.ACCESS_TOKEN, id_token: TEST_TOKENS.IDTOKEN_V2_ALT, scope: "User.Read", @@ -455,8 +471,11 @@ describe("NativeInteractionClient Tests", () => { client_info: raw_client_info, account: { id: "different-nativeAccountId", + properties: {}, + userName: "test_username", }, properties: {}, + state: "", }; jest.spyOn( @@ -467,7 +486,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(mockWamResponse); }); nativeInteractionClient @@ -487,7 +506,7 @@ describe("NativeInteractionClient Tests", () => { const raw_client_info = "eyJ1aWQiOiAiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIiwgInV0aWQiOiI3MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcifQ=="; - const mockWamResponse = { + const mockWamResponse: PlatformBrokerResponse = { access_token: TEST_TOKENS.ACCESS_TOKEN, id_token: TEST_TOKENS.IDTOKEN_V2_ALT, scope: "User.Read", @@ -495,8 +514,11 @@ describe("NativeInteractionClient Tests", () => { client_info: raw_client_info, account: { id: "different-nativeAccountId", + properties: {}, + userName: "test_username", }, properties: {}, + state: "", }; jest.spyOn( @@ -507,7 +529,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(mockWamResponse); }); @@ -540,12 +562,14 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((nativeRequest): Promise => { - expect( - nativeRequest.request && nativeRequest.request.prompt - ).toBe(PromptValue.NONE); - return Promise.resolve(MOCK_WAM_RESPONSE); - }); + ).mockImplementation( + (nativeRequest): Promise => { + expect(nativeRequest && nativeRequest.prompt).toBe( + PromptValue.NONE + ); + return Promise.resolve(MOCK_WAM_RESPONSE); + } + ); // @ts-ignore const nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore @@ -591,12 +615,14 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((nativeRequest): Promise => { - expect( - nativeRequest.request && nativeRequest.request.prompt - ).toBe(PromptValue.NONE); - return Promise.resolve(MOCK_WAM_RESPONSE); - }); + ).mockImplementation( + (nativeRequest): Promise => { + expect(nativeRequest && nativeRequest.prompt).toBe( + PromptValue.NONE + ); + return Promise.resolve(MOCK_WAM_RESPONSE); + } + ); // @ts-ignore const nativeInteractionClient = new PlatformAuthInteractionClient( // @ts-ignore @@ -642,10 +668,10 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { - expect( - message.request?.extraParameters!["x-client-xtra-sku"] - ).toEqual(`${BrowserConstants.MSAL_SKU}|${version},|,|,|`); + ).mockImplementation((request): Promise => { + expect(request?.extraParameters!["x-client-xtra-sku"]).toEqual( + `${BrowserConstants.MSAL_SKU}|${version},|,|,|` + ); return Promise.resolve(MOCK_WAM_RESPONSE); }); await nativeInteractionClient.acquireToken({ @@ -657,10 +683,8 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { - expect( - message.request?.extraParameters!["x-client-xtra-sku"] - ).toEqual( + ).mockImplementation((request): Promise => { + expect(request.extraParameters!["x-client-xtra-sku"]).toEqual( `${BrowserConstants.MSAL_SKU}|${version},|,chrome|1.0.2,|` ); return Promise.resolve(MOCK_WAM_RESPONSE); @@ -705,10 +729,8 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { - expect( - message.request?.extraParameters!["x-client-xtra-sku"] - ).toEqual( + ).mockImplementation((request): Promise => { + expect(request.extraParameters!["x-client-xtra-sku"]).toEqual( `${BrowserConstants.MSAL_SKU}|${version},|,unknown|2.3.4,|` ); return Promise.resolve(MOCK_WAM_RESPONSE); @@ -753,7 +775,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { + ).mockImplementation((message): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); @@ -777,7 +799,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { + ).mockImplementation((message): Promise => { return Promise.reject( new NativeAuthError("test_native_error_code") ); @@ -806,18 +828,22 @@ describe("NativeInteractionClient Tests", () => { .spyOn(PlatformAuthExtensionHandler.prototype, "sendMessage") .mockImplementation(); sendMessageStub - .mockImplementationOnce((message): Promise => { - return Promise.reject( - new NativeAuthError( - "test_native_error_code", - "test_error_desc", - { status: NativeStatusCodes.PERSISTENT_ERROR } - ) - ); - }) - .mockImplementationOnce((message): Promise => { - return Promise.resolve(MOCK_WAM_RESPONSE); - }); + .mockImplementationOnce( + (message): Promise => { + return Promise.reject( + new NativeAuthError( + "test_native_error_code", + "test_error_desc", + { status: NativeStatusCodes.PERSISTENT_ERROR } + ) + ); + } + ) + .mockImplementationOnce( + (message): Promise => { + return Promise.resolve(MOCK_WAM_RESPONSE); + } + ); try { await nativeInteractionClient.acquireToken({ @@ -953,7 +979,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); nativeInteractionClient.acquireTokenRedirect( @@ -975,7 +1001,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); const callbackId = pca.addPerformanceCallback((events) => { @@ -996,7 +1022,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.reject( new NativeAuthError( "ContentError", @@ -1027,10 +1053,10 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { - expect( - message.request?.extraParameters!["x-client-xtra-sku"] - ).toEqual(`${BrowserConstants.MSAL_SKU}|${version},|,|,|`); + ).mockImplementation((request): Promise => { + expect(request.extraParameters!["x-client-xtra-sku"]).toEqual( + `${BrowserConstants.MSAL_SKU}|${version},|,|,|` + ); return Promise.resolve(MOCK_WAM_RESPONSE); }); nativeInteractionClient.acquireTokenRedirect( @@ -1063,7 +1089,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((message): Promise => { + ).mockImplementation((message): Promise => { return Promise.reject( new NativeAuthError("test_native_error_code") ); @@ -1088,21 +1114,27 @@ describe("NativeInteractionClient Tests", () => { "sendMessage" ); sendMessageStub - .mockImplementationOnce((message): Promise => { - return Promise.reject( - new NativeAuthError( - "test_native_error_code", - "test_error_desc", - { status: NativeStatusCodes.PERSISTENT_ERROR } - ) - ); - }) - .mockImplementationOnce((message): Promise => { - return Promise.resolve(MOCK_WAM_RESPONSE); - }) - .mockImplementationOnce((message): Promise => { - return Promise.resolve(MOCK_WAM_RESPONSE); - }); + .mockImplementationOnce( + (message): Promise => { + return Promise.reject( + new NativeAuthError( + "test_native_error_code", + "test_error_desc", + { status: NativeStatusCodes.PERSISTENT_ERROR } + ) + ); + } + ) + .mockImplementationOnce( + (message): Promise => { + return Promise.resolve(MOCK_WAM_RESPONSE); + } + ) + .mockImplementationOnce( + (message): Promise => { + return Promise.resolve(MOCK_WAM_RESPONSE); + } + ); try { await nativeInteractionClient.acquireTokenRedirect( @@ -1184,7 +1216,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); // @ts-ignore @@ -1208,7 +1240,7 @@ describe("NativeInteractionClient Tests", () => { idTokenClaims: ID_TOKEN_CLAIMS, accessToken: MOCK_WAM_RESPONSE.access_token, fromCache: false, - state: undefined, + state: "", correlationId: RANDOM_TEST_GUID, expiresOn: response && response.expiresOn, // Steal the expires on from the response as this is variable account: TEST_ACCOUNT_INFO, @@ -1231,10 +1263,10 @@ describe("NativeInteractionClient Tests", () => { PlatformAuthExtensionHandler.prototype, "sendMessage" ).mockImplementation( - (messageBody: NativeExtensionRequestBody): Promise => { - expect( - messageBody.request && messageBody.request.prompt - ).toBe(undefined); + ( + request: PlatformBrokerRequest + ): Promise => { + expect(request && request.prompt).toBe(undefined); return Promise.resolve(MOCK_WAM_RESPONSE); } ); @@ -1260,7 +1292,7 @@ describe("NativeInteractionClient Tests", () => { idTokenClaims: ID_TOKEN_CLAIMS, accessToken: MOCK_WAM_RESPONSE.access_token, fromCache: false, - state: undefined, + state: "", correlationId: RANDOM_TEST_GUID, expiresOn: response && response.expiresOn, // Steal the expires on from the response as this is variable account: TEST_ACCOUNT_INFO, @@ -1283,7 +1315,7 @@ describe("NativeInteractionClient Tests", () => { jest.spyOn( PlatformAuthExtensionHandler.prototype, "sendMessage" - ).mockImplementation((): Promise => { + ).mockImplementation((): Promise => { return Promise.resolve(MOCK_WAM_RESPONSE); }); await nativeInteractionClient.acquireTokenRedirect( From 6a519bceeae892d99375ffc46db87f684e258911 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Fri, 9 May 2025 08:25:15 -0700 Subject: [PATCH 23/30] added tests for PlatformAuthDOMHandler --- .../nativeBroker/PlatformAuthDOMHandler.ts | 14 +- .../test/app/PublicClientApplication.spec.ts | 104 ++-- .../broker/PlatformAuthDOMHandler.spec.ts | 458 ++++++++++++++++++ 3 files changed, 537 insertions(+), 39 deletions(-) create mode 100644 lib/msal-browser/test/broker/PlatformAuthDOMHandler.spec.ts diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index 5cad48d91e..a30e89d6f7 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -103,7 +103,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { try { const platformDOMRequest: PlatformDOMTokenRequest = - await this.initializePlatformDOMRequest(request); + this.initializePlatformDOMRequest(request); const response: object = // @ts-ignore await window.navigator.platformAuthentication.executeGetToken( @@ -118,9 +118,9 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { } } - private async initializePlatformDOMRequest( + private initializePlatformDOMRequest( request: PlatformBrokerRequest - ): Promise { + ): PlatformDOMTokenRequest { this.logger.trace( "NativeInteractionClient: initializeNativeDOMRequest called" ); @@ -180,7 +180,11 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { ); } else if (response.hasOwnProperty("error")) { const errorResponse = response as PlatformDOMTokenResponse; - if (errorResponse.isSuccess === false) { + if ( + errorResponse.isSuccess === false && + errorResponse.error && + errorResponse.error.code + ) { this.logger.trace( "PlatformDOMHandler: platform broker returned error response" ); @@ -216,7 +220,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { scope: response.scopes, state: response.state || "", properties: response.properties || {}, - extendedLifetimeToken: response.extendedLifetimeToken, + extendedLifetimeToken: response.extendedLifetimeToken ?? false, shr: response.proofOfPossessionPayload, }; diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 8ff74da89d..ad803d9ff1 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -118,6 +118,8 @@ import { } from "msal-test-utils"; import { INTERACTION_TYPE } from "../../src/utils/BrowserConstants.js"; import { BaseOperatingContext } from "../../src/operatingcontext/BaseOperatingContext.js"; +import { PlatformAuthDOMHandler } from "../../src/broker/nativeBroker/PlatformAuthDOMHandler.js"; +import { config } from "process"; const cacheConfig = { temporaryCacheLocation: BrowserCacheLocation.SessionStorage, @@ -138,7 +140,7 @@ let testAppConfig = { }, }; -function stubProvider(config: Configuration) { +function stubExtensionProvider(config: Configuration) { const browserEnvironment = typeof window !== "undefined"; const newConfig = buildConfiguration(config, browserEnvironment); @@ -148,7 +150,6 @@ function stubProvider(config: Configuration) { "unittest" ); const performanceClient = newConfig.telemetry.client; - return jest .spyOn(PlatformAuthExtensionHandler, "createProvider") .mockImplementation(async () => { @@ -161,6 +162,28 @@ function stubProvider(config: Configuration) { }); } +function stubDOMProvider(config: Configuration) { + const browserEnvironment = typeof window !== "undefined"; + + const newConfig = buildConfiguration(config, browserEnvironment); + const logger = new Logger( + newConfig.system.loggerOptions, + "unittest", + "unittest" + ); + const performanceClient = newConfig.telemetry.client; + console.log("stubDOMProvider"); + return jest + .spyOn(PlatformAuthDOMHandler, "createProvider") + .mockImplementation(async () => { + return new PlatformAuthDOMHandler( + logger, + performanceClient, + "test-correlation-id" + ); + }); +} + const testRequest: CommonAuthorizationUrlRequest = { redirectUri: `${TEST_URIS.DEFAULT_INSTANCE}/`, scopes: TEST_CONFIG.DEFAULT_SCOPES, @@ -451,7 +474,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { } }); - it("creates extension provider if allowPlatformBroker is true", async () => { + it("creates platform auth extension handler if allowPlatformBroker is true", async () => { const config = { auth: { clientId: TEST_CONFIG.MSAL_CLIENT_ID, @@ -467,9 +490,15 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ).mockImplementation(() => { return false; }); + + const getPlatformAuthProviderSpy = jest.spyOn( + PlatformAuthProvider, + "getPlatformAuthProvider" + ); + pca = new PublicClientApplication(config); - const createProviderSpy = stubProvider(config); + const createExtensionProviderSpy = stubExtensionProvider(config); await pca.initialize(); @@ -477,7 +506,8 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any pca = (pca as any).controller; - expect(createProviderSpy).toHaveBeenCalled(); + expect(getPlatformAuthProviderSpy).toHaveBeenCalled(); + expect(createExtensionProviderSpy).toHaveBeenCalled(); // @ts-ignore expect(pca.platformAuthProvider).toBeInstanceOf( PlatformAuthExtensionHandler @@ -485,24 +515,30 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }); it("does not create extension provider if allowPlatformBroker is false", async () => { - const createProviderSpy = jest.spyOn( - PlatformAuthExtensionHandler, - "createProvider" + const getPlatformAuthProviderSpy = jest.spyOn( + PlatformAuthProvider, + "getPlatformAuthProvider" ); - pca = new PublicClientApplication({ + + const config = { auth: { clientId: TEST_CONFIG.MSAL_CLIENT_ID, }, system: { allowPlatformBroker: false, }, - }); + }; + + pca = new PublicClientApplication(config); + const createProviderSpy = stubExtensionProvider(config); + await pca.initialize(); //Implementation of PCA was moved to controller. pca = (pca as any).controller; expect(createProviderSpy).toHaveBeenCalledTimes(0); + expect(getPlatformAuthProviderSpy).not.toHaveBeenCalled(); // @ts-ignore expect(pca.platformAuthProvider).toBeUndefined(); }); @@ -777,7 +813,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); // Implementation of PCA was moved to controller. @@ -871,7 +907,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }, }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); pca.initialize().then(() => { const callbackId = pca.addPerformanceCallback((events) => { @@ -970,7 +1006,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); //@ts-ignore pca.controller.browserStorage.setInteractionInProgress(true); @@ -1571,7 +1607,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -1626,7 +1662,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); const callbackId = pca.addPerformanceCallback((events) => { expect(events.length).toBeGreaterThanOrEqual(1); @@ -1665,7 +1701,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { pca = new PublicClientApplication(config); await pca.initialize(); - stubProvider(config); + stubExtensionProvider(config); //Implementation of PCA was moved to controller. pca = (pca as any).controller; @@ -1707,7 +1743,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); // Implementation of PCA was moved to controller. @@ -1754,7 +1790,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); // Implementation of PCA was moved to controller. @@ -1803,7 +1839,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //PCA implementation moved to controller @@ -2107,7 +2143,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }, }; - stubProvider(config); + stubExtensionProvider(config); pca = new PublicClientApplication({ ...config, telemetry: { @@ -2519,7 +2555,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -2582,7 +2618,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); const testAccount: AccountInfo = { @@ -2637,7 +2673,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -2695,7 +2731,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -2755,7 +2791,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //PCA implementation moved to controller @@ -3308,7 +3344,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -3365,7 +3401,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -3423,7 +3459,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -3714,7 +3750,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -3766,7 +3802,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -4211,7 +4247,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -4268,7 +4304,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. @@ -4328,7 +4364,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. pca = (pca as any).controller; @@ -7311,7 +7347,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }; pca = new PublicClientApplication(config); - stubProvider(config); + stubExtensionProvider(config); await pca.initialize(); //Implementation of PCA was moved to controller. diff --git a/lib/msal-browser/test/broker/PlatformAuthDOMHandler.spec.ts b/lib/msal-browser/test/broker/PlatformAuthDOMHandler.spec.ts new file mode 100644 index 0000000000..6e556bd592 --- /dev/null +++ b/lib/msal-browser/test/broker/PlatformAuthDOMHandler.spec.ts @@ -0,0 +1,458 @@ +import { + AuthError, + AuthErrorCodes, + IPerformanceClient, + Logger, +} from "@azure/msal-common/browser"; +import { PlatformAuthConstants } from "../../src/utils/BrowserConstants.js"; +import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; +import { PlatformAuthDOMHandler } from "../../src/broker/nativeBroker/PlatformAuthDOMHandler.js"; +import { get } from "http"; +import { PlatformBrokerResponse } from "../../src/broker/nativeBroker/PlatformBrokerResponse.js"; +import { + TEST_CONFIG, + TEST_TOKENS, + TEST_URIS, +} from "../utils/StringConstants.js"; +import { PlatformBrokerRequest } from "../../src/broker/nativeBroker/PlatformBrokerRequest.js"; +import { NativeAuthError } from "../../src/error/NativeAuthError.js"; + +describe("PlatformAuthDOMHandler tests", () => { + let performanceClient: IPerformanceClient; + let logger: Logger; + + let getSupportedContractsMock: jest.Mock; + let executeGetTokenMock: jest.Mock; + beforeEach(() => { + performanceClient = getDefaultPerformanceClient(); + logger = new Logger({}, "test", "1.0.0"); + + getSupportedContractsMock = jest.fn(); + executeGetTokenMock = jest.fn(); + Object.defineProperty(window.navigator, "platformAuthentication", { + value: { + getSupportedContracts: getSupportedContractsMock, + executeGetToken: executeGetTokenMock, + }, + writable: true, + }); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe("createProvider tests", () => { + it("should return PlatformAuthDOMHandler when DOM APIs are available for platform auth", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(getSupportedContractsMock).toHaveBeenCalled(); + expect(platformAuthDOMHandler).toBeInstanceOf( + PlatformAuthDOMHandler + ); + }); + + it("should return undefined when DOM APIs are not available for platform auth", async () => { + getSupportedContractsMock.mockResolvedValue([]); + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(getSupportedContractsMock).toHaveBeenCalled(); + expect(platformAuthDOMHandler).toBe(undefined); + }); + }); + + describe("getExtensionId tests", () => { + it("should return the correct extension ID", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(platformAuthDOMHandler).toBeInstanceOf( + PlatformAuthDOMHandler + ); + const brokerId = platformAuthDOMHandler?.getExtensionId(); + expect(brokerId).toBe( + PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID + ); + }); + }); + + describe("getExtensionVersion tests", () => { + it("should return empty string for extensionVersion", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(platformAuthDOMHandler).toBeInstanceOf( + PlatformAuthDOMHandler + ); + const brokerId = platformAuthDOMHandler?.getExtensionVersion(); + expect(brokerId).toBe(""); + }); + }); + + describe("getExtensionName tests", () => { + it("should return corect extensionName", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(platformAuthDOMHandler).toBeInstanceOf( + PlatformAuthDOMHandler + ); + const brokerId = platformAuthDOMHandler?.getExtensionName(); + expect(brokerId).toBe(PlatformAuthConstants.DOM_API_NAME); + }); + }); + + describe("sendMessage and validatePlatformBrokerResponse tests", () => { + it("returns PlatformBrokerResponse success response for valid request to DOM API", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const testRequest: PlatformBrokerRequest = { + accountId: "test-id", + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + authority: TEST_CONFIG.validAuthority, + redirectUri: TEST_URIS.TEST_REDIR_URI, + scope: "read openid", + correlationId: TEST_CONFIG.CORRELATION_ID, + windowTitleSubstring: "", + extraParameters: { + extendedExpiryToken: "true", + }, + }; + const testDOMResponse: object = { + isSuccess: true, + state: "", + accessToken: TEST_TOKENS.ACCESS_TOKEN, + expiresIn: 6000, + account: { + id: "test-id", + userName: "test-user", + properties: {}, + }, + clientInfo: "test-client-info", + idToken: TEST_TOKENS.IDTOKEN_V1, + scopes: "read openid", + error: {}, + properties: { + MATS: '{"MATS":"{"x_ms_clitelem":"1,0,0,,I","ui_visible":true}"}', + }, + extendedLifetimeToken: true, + }; + const validatedResponse: PlatformBrokerResponse = { + access_token: TEST_TOKENS.ACCESS_TOKEN, + account: { + id: "test-id", + userName: "test-user", + properties: {}, + }, + client_info: "test-client-info", + expires_in: 6000, + id_token: TEST_TOKENS.IDTOKEN_V1, + properties: { + MATS: '{"MATS":"{"x_ms_clitelem":"1,0,0,,I","ui_visible":true}"}', + }, + scope: "read openid", + state: "", + extendedLifetimeToken: true, + shr: undefined, + }; + executeGetTokenMock.mockResolvedValue(testDOMResponse); + + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + const platformBrokerResponse = + await platformAuthDOMHandler?.sendMessage(testRequest); + expect(platformBrokerResponse).toEqual(validatedResponse); + }); + + it("returns unexpected_error when token response is missing required properties with isSuccess = true", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const testRequest: PlatformBrokerRequest = { + accountId: "test-id", + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + authority: TEST_CONFIG.validAuthority, + redirectUri: TEST_URIS.TEST_REDIR_URI, + scope: "read openid", + correlationId: TEST_CONFIG.CORRELATION_ID, + windowTitleSubstring: "", + extraParameters: { + extendedExpiryToken: "true", + }, + }; + const testDOMResponse: object = { + isSuccess: true, + state: "", + expiresIn: 6000, + account: { + id: "test-id", + userName: "test-user", + properties: {}, + }, + clientInfo: "test-client-info", + scopes: "read openid", + error: {}, + properties: { + MATS: '{"MATS":"{"x_ms_clitelem":"1,0,0,,I","ui_visible":true}"}', + }, + extendedLifetimeToken: true, + }; + + executeGetTokenMock.mockResolvedValue(testDOMResponse); + + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + try { + const platformBrokerResponse = + await platformAuthDOMHandler?.sendMessage(testRequest); + throw "sendMessage should have thrown an error"; + } catch (e) { + expect(e).toBeInstanceOf(AuthError); + expect((e as AuthError).errorCode).toEqual( + AuthErrorCodes.unexpectedError + ); + expect((e as AuthError).errorMessage).toContain( + "Response missing expected properties." + ); + } + }); + + it("returns unexpected_error when required error properties missing from response with isSuccess = false", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const testRequest: PlatformBrokerRequest = { + accountId: "test-id", + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + authority: TEST_CONFIG.validAuthority, + redirectUri: TEST_URIS.TEST_REDIR_URI, + scope: "read openid", + correlationId: TEST_CONFIG.CORRELATION_ID, + windowTitleSubstring: "", + extraParameters: { + extendedExpiryToken: "true", + }, + }; + const testDOMResponse: object = { + isSuccess: false, + expiresIn: 0, + extendedLifetimeToken: false, + error: {}, + }; + + executeGetTokenMock.mockResolvedValue(testDOMResponse); + + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + try { + const platformBrokerResponse = + await platformAuthDOMHandler?.sendMessage(testRequest); + throw "sendMessage should have thrown an error"; + } catch (e) { + expect(e).toBeInstanceOf(AuthError); + expect((e as AuthError).errorCode).toEqual( + AuthErrorCodes.unexpectedError + ); + expect((e as AuthError).errorMessage).toContain( + "Response missing expected properties." + ); + } + }); + + it("returns nativeAuthError response for unsuccessful token request", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const testRequest: PlatformBrokerRequest = { + accountId: "test-id", + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + authority: TEST_CONFIG.validAuthority, + redirectUri: TEST_URIS.TEST_REDIR_URI, + scope: "read openid", + correlationId: TEST_CONFIG.CORRELATION_ID, + windowTitleSubstring: "", + extraParameters: { + extendedExpiryToken: "true", + }, + }; + const testDOMResponse: object = { + isSuccess: false, + expiresIn: 0, + extendedLifetimeToken: false, + error: { + code: "OSError", + description: "there is an OSError", + errorCode: "-6000", + protocolError: "-5000", + status: "PERSISTENT_ERROR", + properties: {}, + }, + }; + executeGetTokenMock.mockResolvedValue(testDOMResponse); + + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + try { + const platformBrokerResponse = + await platformAuthDOMHandler?.sendMessage(testRequest); + throw "sendMessage should have thrown an error"; + } catch (e) { + expect(e).toBeInstanceOf(NativeAuthError); + expect((e as NativeAuthError).errorCode).toEqual("OSError"); + expect((e as NativeAuthError).errorMessage).toEqual( + (testDOMResponse as any).error.description + ); + } + }); + }); + + describe("initializePlatformDOMRequest tests", () => { + it("should return a valid PlatformDOMTokenRequest object", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + const testRequest: PlatformBrokerRequest = { + accountId: "test-id", + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + authority: TEST_CONFIG.validAuthority, + redirectUri: TEST_URIS.TEST_REDIR_URI, + scope: "read openid", + correlationId: TEST_CONFIG.CORRELATION_ID, + windowTitleSubstring: "", + extraParameters: { + extendedExpiryToken: "true", + }, + }; + const platformDOMRequest = + //@ts-ignore + platformAuthDOMHandler.initializePlatformDOMRequest( + testRequest + ); + expect(platformDOMRequest).toEqual({ + accountId: testRequest.accountId, + brokerId: PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID, + authority: testRequest.authority, + clientId: testRequest.clientId, + correlationId: testRequest.correlationId, + isSecurityTokenService: false, + extraParameters: { + extendedExpiryToken: "true", + windowTitleSubstring: "", + }, + redirectUri: testRequest.redirectUri, + scope: testRequest.scope, + state: undefined, + storeInCache: undefined, + embeddedClientId: undefined, + }); + }); + }); + + describe("validatePlatformBrokerResponse tests", () => { + it("should return a valid PlatformBrokerResponse object", async () => { + getSupportedContractsMock.mockResolvedValue([ + PlatformAuthConstants.PLATFORM_DOM_APIS, + ]); + const platformAuthDOMHandler = + await PlatformAuthDOMHandler.createProvider( + logger, + performanceClient, + "test-correlation-id" + ); + const testResponse: object = { + isSuccess: true, + state: "", + accessToken: TEST_TOKENS.ACCESS_TOKEN, + expiresIn: 6000, + account: { + id: "test-id", + userName: "test-user", + properties: {}, + }, + clientInfo: "test-client-info", + idToken: TEST_TOKENS.IDTOKEN_V1, + scopes: "read openid", + error: {}, + properties: { + MATS: '{"MATS":"{"x_ms_clitelem":"1,0,0,,I","ui_visible":true}"}', + }, + extendedLifetimeToken: true, + }; + const validatedResponse = + //@ts-ignore + platformAuthDOMHandler.validatePlatformBrokerResponse( + testResponse + ); + expect(validatedResponse).toEqual({ + access_token: TEST_TOKENS.ACCESS_TOKEN, + account: { + id: "test-id", + userName: "test-user", + properties: {}, + }, + client_info: "test-client-info", + expires_in: 6000, + id_token: TEST_TOKENS.IDTOKEN_V1, + properties: { + MATS: '{"MATS":"{"x_ms_clitelem":"1,0,0,,I","ui_visible":true}"}', + }, + scope: "read openid", + state: "", + extendedLifetimeToken: true, + }); + }); + }); +}); From 75f3721c99d1c100c732edad9a6950a0db4d774f Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Fri, 9 May 2025 08:30:01 -0700 Subject: [PATCH 24/30] removing console statement --- lib/msal-browser/test/app/PublicClientApplication.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index ad803d9ff1..41d7710069 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -172,7 +172,6 @@ function stubDOMProvider(config: Configuration) { "unittest" ); const performanceClient = newConfig.telemetry.client; - console.log("stubDOMProvider"); return jest .spyOn(PlatformAuthDOMHandler, "createProvider") .mockImplementation(async () => { From d4339e96274aae82c2bc44eea5cce799a1228696 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Fri, 9 May 2025 15:40:43 -0700 Subject: [PATCH 25/30] small updates --- .../nativeBroker/PlatformAuthProvider.ts | 2 +- .../src/controllers/StandardController.ts | 2 +- .../operatingcontext/BaseOperatingContext.ts | 1 + .../test/app/PublicClientApplication.spec.ts | 37 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index 16f97d2c33..faccdb4530 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -41,7 +41,7 @@ export async function isPlatformBrokerAvailable( const performanceClient = perfClient || new StubPerformanceClient(); - if (!window) { + if (typeof window === "undefined") { logger.trace("Non DOM environment detected, returning false"); return false; } diff --git a/lib/msal-browser/src/controllers/StandardController.ts b/lib/msal-browser/src/controllers/StandardController.ts index 6b4db400ad..0c9a090388 100644 --- a/lib/msal-browser/src/controllers/StandardController.ts +++ b/lib/msal-browser/src/controllers/StandardController.ts @@ -1622,7 +1622,7 @@ export class StandardController implements IController { ) ) { this.logger.trace( - "canUsePlatformBroker: isPlatformBrokerAvailable returned false, returning false" + "canUsePlatformBroker: isBrokerAvailable returned false, returning false" ); return false; } diff --git a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts index c615265c24..300259bc9a 100644 --- a/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts +++ b/lib/msal-browser/src/operatingcontext/BaseOperatingContext.ts @@ -62,6 +62,7 @@ export abstract class BaseOperatingContext { */ this.browserEnvironment = typeof window !== "undefined"; this.config = buildConfiguration(config, this.browserEnvironment); + let sessionStorage: Storage | undefined; try { sessionStorage = window[BrowserCacheLocation.SessionStorage]; diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 41d7710069..2ae8593ddd 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -542,6 +542,43 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(pca.platformAuthProvider).toBeUndefined(); }); + it("creates platform auth dom handler if allowPlatformBroker is true and dom APIs are present", async () => { + const getPlatformAuthProviderSpy = jest.spyOn( + PlatformAuthProvider, + "getPlatformAuthProvider" + ); + + const config = { + auth: { + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + }, + system: { + allowPlatformBroker: true, + }, + }; + + pca = new PublicClientApplication(config); + window.sessionStorage.setItem( + "msal.browser.platform.auth.dom", + "true" + ); + jest.spyOn(Object.getPrototypeOf(sessionStorage), "getItem"); + + const createDOMProviderSpy = stubDOMProvider(config); + await pca.initialize(); + + // Implementation of PCA was moved to controller. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + pca = (pca as any).controller; + + expect(getPlatformAuthProviderSpy).toHaveBeenCalled(); + expect(createDOMProviderSpy).toHaveBeenCalled(); + // @ts-ignore + expect(pca.platformAuthProvider).toBeInstanceOf( + PlatformAuthDOMHandler + ); + }); + it("catches error if extension provider fails to initialize", async () => { const createProviderSpy = jest .spyOn(PlatformAuthExtensionHandler, "createProvider") From 3f0455ee959399f780c93035a46832fcc7b2ed16 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 12 May 2025 14:29:35 -0700 Subject: [PATCH 26/30] addressing comments and added unit tests --- .../nativeBroker/PlatformAuthDOMHandler.ts | 8 +- .../nativeBroker/PlatformAuthProvider.ts | 13 +- .../test/app/PublicClientApplication.spec.ts | 1 - .../test/broker/PlatformAuthProvider.spec.ts | 277 ++++++++++++++++++ 4 files changed, 287 insertions(+), 12 deletions(-) create mode 100644 lib/msal-browser/test/broker/PlatformAuthProvider.spec.ts diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index a30e89d6f7..05e2f19056 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -26,8 +26,6 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { protected logger: Logger; protected performanceClient: IPerformanceClient; protected correlationId: string; - protected brokerId: string; - protected extensionVersion: string; platformAuthType: string; constructor( @@ -37,9 +35,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { ) { this.logger = logger; this.performanceClient = performanceClient; - this.brokerId = PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID; this.correlationId = correlationId; - this.extensionVersion = ""; this.platformAuthType = PlatformAuthConstants.PLATFORM_DOM_PROVIDER; } @@ -78,11 +74,11 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { * @returns */ getExtensionId(): string { - return this.brokerId; + return PlatformAuthConstants.MICROSOFT_ENTRA_BROKERID; } getExtensionVersion(): string | undefined { - return this.extensionVersion; + return ""; } getExtensionName(): string | undefined { diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index faccdb4530..a176bb4405 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -42,15 +42,15 @@ export async function isPlatformBrokerAvailable( const performanceClient = perfClient || new StubPerformanceClient(); if (typeof window === "undefined") { - logger.trace("Non DOM environment detected, returning false"); + logger.trace("Non-browser environment detected, returning false"); return false; } - return !!getPlatformAuthProvider( + return !!(await getPlatformAuthProvider( logger, performanceClient, correlationId || createNewGuid() - ); + )); } export async function getPlatformAuthProvider( @@ -64,7 +64,8 @@ export async function getPlatformAuthProvider( const enablePlatformBrokerDOMSupport = isDomEnabledForPlatformAuth(); logger.trace( - "Platform auth available via DOM API: " + enablePlatformBrokerDOMSupport + "Has client allowed platform auth via DOM API: " + + enablePlatformBrokerDOMSupport ); let platformAuthProvider: IPlatformAuthHandler | undefined; try { @@ -77,6 +78,9 @@ export async function getPlatformAuthProvider( ); } if (!platformAuthProvider) { + logger.trace( + "Platform auth via DOM API not available, checking for extension" + ); /* * If DOM APIs are not available, check if browser extension is available. * Platform authentication via DOM APIs is preferred over extension APIs. @@ -155,6 +159,5 @@ export function isBrokerAvailable( return false; } } - return true; } diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 2ae8593ddd..8e889e5b9f 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -562,7 +562,6 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { "msal.browser.platform.auth.dom", "true" ); - jest.spyOn(Object.getPrototypeOf(sessionStorage), "getItem"); const createDOMProviderSpy = stubDOMProvider(config); await pca.initialize(); diff --git a/lib/msal-browser/test/broker/PlatformAuthProvider.spec.ts b/lib/msal-browser/test/broker/PlatformAuthProvider.spec.ts new file mode 100644 index 0000000000..0914bb411b --- /dev/null +++ b/lib/msal-browser/test/broker/PlatformAuthProvider.spec.ts @@ -0,0 +1,277 @@ +import { + Logger, + IPerformanceClient, + AuthenticationScheme, +} from "@azure/msal-common/browser"; +import * as PlatformAuthProvider from "../../src/broker/nativeBroker/PlatformAuthProvider.js"; +import { getDefaultPerformanceClient } from "../utils/TelemetryUtils.js"; +import { PlatformAuthDOMHandler } from "../../src/broker/nativeBroker/PlatformAuthDOMHandler.js"; +import { + BrowserConfiguration, + buildConfiguration, + Configuration, +} from "../../src/config/Configuration.js"; +import { PlatformAuthExtensionHandler } from "../../src/broker/nativeBroker/PlatformAuthExtensionHandler.js"; +import exp from "constants"; +import { log } from "console"; +import { BrowserAuthError } from "../../src/index.js"; + +describe("PlatformAuthProvider tests", () => { + function stubExtensionProvider() { + return jest + .spyOn(PlatformAuthExtensionHandler, "createProvider") + .mockImplementation(async () => { + return new PlatformAuthExtensionHandler( + logger, + 2000, + performanceClient, + "test-extensionId" + ); + }); + } + + function stubDOMProvider() { + return jest + .spyOn(PlatformAuthDOMHandler, "createProvider") + .mockImplementation(async () => { + return new PlatformAuthDOMHandler( + logger, + performanceClient, + "test-correlation-id" + ); + }); + } + + let performanceClient: IPerformanceClient; + let logger: Logger; + beforeEach(() => { + performanceClient = getDefaultPerformanceClient(); + logger = new Logger({}, "test", "1.0.0"); + }); + afterEach(() => { + window.sessionStorage.clear(); + jest.restoreAllMocks(); + }); + + describe("isPlatformBrokerAvailable tests", () => { + it("should return false if application is not in browser environment", async () => { + const { window } = global; + //@ts-ignore + delete global.window; + const result = await PlatformAuthProvider.isPlatformBrokerAvailable( + {}, + performanceClient, + "test-correlation-id" + ); + expect(result).toBe(false); + global.window = window; // Restore window + }); + + it("should return true if its a browser app and dom handler is available", async () => { + window.sessionStorage.setItem( + "msal.browser.platform.auth.dom", + "true" + ); + const getItemSpy = jest.spyOn( + Object.getPrototypeOf(sessionStorage), + "getItem" + ); + + const domProviderSpy = stubDOMProvider(); + + const result = + await PlatformAuthProvider.isPlatformBrokerAvailable(); + expect(result).toBe(true); + expect(getItemSpy).toHaveBeenCalled(); + expect(domProviderSpy).toHaveBeenCalled(); + }); + + it("should return true if its a browser app and extension handler is available", async () => { + const extensionProviderSpy = stubExtensionProvider(); + + const result = + await PlatformAuthProvider.isPlatformBrokerAvailable(); + expect(result).toBe(true); + expect(extensionProviderSpy).toHaveBeenCalled(); + }); + + it("should return false if no handler is available", async () => { + jest.spyOn( + PlatformAuthDOMHandler, + "createProvider" + ).mockImplementation(async () => { + throw new Error("No handler available"); + }); + + jest.spyOn( + PlatformAuthExtensionHandler, + "createProvider" + ).mockImplementation(async () => { + throw new Error("No handler available"); + }); + + const result = + await PlatformAuthProvider.isPlatformBrokerAvailable(); + expect(result).toBe(false); + }); + }); + + describe("getPlatformAuthProvider tests", () => { + it("should return undefined if no provider is available", async () => { + jest.spyOn( + PlatformAuthDOMHandler, + "createProvider" + ).mockImplementation(async () => { + throw new Error("No handler available"); + }); + + jest.spyOn( + PlatformAuthExtensionHandler, + "createProvider" + ).mockImplementation(async () => { + throw new Error("No handler available"); + }); + + const result = await PlatformAuthProvider.getPlatformAuthProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(result).toBe(undefined); + }); + + it("returns dom handler when available", async () => { + window.sessionStorage.setItem( + "msal.browser.platform.auth.dom", + "true" + ); + const getItemSpy = jest.spyOn( + Object.getPrototypeOf(sessionStorage), + "getItem" + ); + + const domProviderSpy = stubDOMProvider(); + + const result = await PlatformAuthProvider.getPlatformAuthProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(result).not.toBe(undefined); + expect(result).toBeInstanceOf(PlatformAuthDOMHandler); + expect(getItemSpy).toHaveBeenCalled(); + expect(domProviderSpy).toHaveBeenCalled(); + }); + + it("returns extension handler if dom APIs are not available and extension is available", async () => { + const extensionProviderSpy = stubExtensionProvider(); + + const result = await PlatformAuthProvider.getPlatformAuthProvider( + logger, + performanceClient, + "test-correlation-id" + ); + expect(result).not.toBe(undefined); + expect(result).toBeInstanceOf(PlatformAuthExtensionHandler); + expect(extensionProviderSpy).toHaveBeenCalled(); + }); + }); + + describe("isDomEnabledForPlatformAuth tests", () => { + it("should return false if session storage is not set with DOM API flag", () => { + expect(PlatformAuthProvider.isDomEnabledForPlatformAuth()).toBe( + false + ); + }); + + it("should return true if session storage is set with DOM API flag", () => { + window.sessionStorage.setItem( + "msal.browser.platform.auth.dom", + "true" + ); + expect(PlatformAuthProvider.isDomEnabledForPlatformAuth()).toBe( + true + ); + }); + + it("should return false if session storage errors out", () => { + const { sessionStorage } = global.window; + //@ts-ignore + delete global.window.sessionStorage; + const result = PlatformAuthProvider.isDomEnabledForPlatformAuth(); + expect(result).toBe(false); + global.window.sessionStorage = sessionStorage; // Restore sessionStorage + }); + }); + + describe("isBrokerAvailable", () => { + let config: BrowserConfiguration; + beforeEach(() => { + config = buildConfiguration( + { + auth: { + clientId: "test-client-id", + authority: "https://login.microsoftonline.com/common", + redirectUri: "http://localhost", + }, + system: { + allowPlatformBroker: true, + }, + }, + true + ); + }); + + it("returns false when config is not set to enable paltform broker", () => { + config.system.allowPlatformBroker = false; + const result = PlatformAuthProvider.isBrokerAvailable( + config, + logger, + new PlatformAuthDOMHandler( + logger, + performanceClient, + "test-correlation-id" + ), + AuthenticationScheme.BEARER + ); + expect(result).toBe(false); + }); + + it("returns false when platform auth provider is not initialized", () => { + const result = PlatformAuthProvider.isBrokerAvailable( + config, + logger, + undefined, + AuthenticationScheme.BEARER + ); + expect(result).toBe(false); + }); + it("returns false when authentication scheme is not supported", () => { + const result = PlatformAuthProvider.isBrokerAvailable( + config, + logger, + new PlatformAuthDOMHandler( + logger, + performanceClient, + "test-correlation-id" + ), + "unknown-scheme" as AuthenticationScheme + ); + expect(result).toBe(false); + }); + + it("returns true when platform auth provider is initialized and authentication scheme is supported", () => { + const result = PlatformAuthProvider.isBrokerAvailable( + config, + logger, + new PlatformAuthDOMHandler( + logger, + performanceClient, + "test-correlation-id" + ), + AuthenticationScheme.BEARER + ); + expect(result).toBe(true); + }); + }); +}); From 05570d35e7b527eb1d5598e9afab9121258b3fd5 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 12 May 2025 14:59:36 -0700 Subject: [PATCH 27/30] Update lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts Co-authored-by: Thomas Norling --- lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts index a176bb4405..d5b054ee22 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts @@ -102,6 +102,7 @@ export async function getPlatformAuthProvider( /** * Returns true if the DOM API support for platform auth is enabled in session storage * @returns boolean + * @deprecated */ export function isDomEnabledForPlatformAuth(): boolean { let sessionStorage: Storage | undefined; From e975305265d809d675396602e4a4b180f2e54f58 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 12 May 2025 15:50:58 -0700 Subject: [PATCH 28/30] updating msal-browser-api --- .../apiReview/msal-browser.api.md | 553 ++++++++++++------ 1 file changed, 381 insertions(+), 172 deletions(-) diff --git a/lib/msal-browser/apiReview/msal-browser.api.md b/lib/msal-browser/apiReview/msal-browser.api.md index 4bf1522d20..8c626421a5 100644 --- a/lib/msal-browser/apiReview/msal-browser.api.md +++ b/lib/msal-browser/apiReview/msal-browser.api.md @@ -3,69 +3,68 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts - -import { AccountEntity } from '@azure/msal-common/browser'; -import { AccountFilter } from '@azure/msal-common/browser'; -import { AccountInfo } from '@azure/msal-common/browser'; -import { ApplicationTelemetry } from '@azure/msal-common/browser'; -import { AuthenticationHeaderParser } from '@azure/msal-common/browser'; -import { AuthenticationResult as AuthenticationResult_2 } from '@azure/msal-common/browser'; -import { AuthenticationScheme } from '@azure/msal-common/browser'; -import { AuthError } from '@azure/msal-common/browser'; -import { AuthErrorCodes } from '@azure/msal-common/browser'; -import { AuthErrorMessage } from '@azure/msal-common/browser'; -import { AzureCloudInstance } from '@azure/msal-common/browser'; -import { AzureCloudOptions } from '@azure/msal-common/browser'; -import { ClientAuthError } from '@azure/msal-common/browser'; -import { ClientAuthErrorCodes } from '@azure/msal-common/browser'; -import { ClientAuthErrorMessage } from '@azure/msal-common/browser'; -import { ClientConfigurationError } from '@azure/msal-common/browser'; -import { ClientConfigurationErrorCodes } from '@azure/msal-common/browser'; -import { ClientConfigurationErrorMessage } from '@azure/msal-common/browser'; -import { CommonAuthorizationCodeRequest } from '@azure/msal-common/browser'; -import { CommonAuthorizationUrlRequest } from '@azure/msal-common/browser'; -import { CommonEndSessionRequest } from '@azure/msal-common/browser'; -import { CommonSilentFlowRequest } from '@azure/msal-common/browser'; -import { ExternalTokenResponse } from '@azure/msal-common/browser'; -import { IdTokenClaims } from '@azure/msal-common/browser'; -import { ILoggerCallback } from '@azure/msal-common/browser'; -import { INetworkModule } from '@azure/msal-common/browser'; -import { InProgressPerformanceEvent } from '@azure/msal-common/browser'; -import { InteractionRequiredAuthError } from '@azure/msal-common/browser'; -import { InteractionRequiredAuthErrorCodes } from '@azure/msal-common/browser'; -import { InteractionRequiredAuthErrorMessage } from '@azure/msal-common/browser'; -import { invoke } from '@azure/msal-common/browser'; -import { invokeAsync } from '@azure/msal-common/browser'; -import { IPerformanceClient } from '@azure/msal-common/browser'; -import { IPerformanceMeasurement } from '@azure/msal-common/browser'; -import { JsonWebTokenTypes } from '@azure/msal-common/browser'; -import { Logger } from '@azure/msal-common/browser'; -import { LoggerOptions } from '@azure/msal-common/browser'; -import { LogLevel } from '@azure/msal-common/browser'; -import { NetworkRequestOptions } from '@azure/msal-common/browser'; -import { NetworkResponse } from '@azure/msal-common/browser'; -import { OIDC_DEFAULT_SCOPES } from '@azure/msal-common/browser'; -import { OIDCOptions } from '@azure/msal-common/browser'; -import { PerformanceCallbackFunction } from '@azure/msal-common/browser'; -import { PerformanceClient } from '@azure/msal-common/browser'; -import { PerformanceEvent } from '@azure/msal-common/browser'; -import { PerformanceEvents } from '@azure/msal-common/browser'; -import { PromptValue } from '@azure/msal-common/browser'; -import { ProtocolMode } from '@azure/msal-common/browser'; -import { ServerError } from '@azure/msal-common/browser'; -import { ServerResponseType } from '@azure/msal-common/browser'; -import { SignedHttpRequestParameters } from '@azure/msal-common/browser'; -import { StringDict } from '@azure/msal-common/browser'; -import { StringUtils } from '@azure/msal-common/browser'; -import { StubPerformanceClient } from '@azure/msal-common/browser'; -import { SubMeasurement } from '@azure/msal-common/browser'; -import { SystemOptions } from '@azure/msal-common/browser'; -import { TenantProfile } from '@azure/msal-common/browser'; -import { UrlString } from '@azure/msal-common/browser'; - -export { AccountEntity } - -export { AccountInfo } +import { AccountEntity } from "@azure/msal-common/browser"; +import { AccountFilter } from "@azure/msal-common/browser"; +import { AccountInfo } from "@azure/msal-common/browser"; +import { ApplicationTelemetry } from "@azure/msal-common/browser"; +import { AuthenticationHeaderParser } from "@azure/msal-common/browser"; +import { AuthenticationResult as AuthenticationResult_2 } from "@azure/msal-common/browser"; +import { AuthenticationScheme } from "@azure/msal-common/browser"; +import { AuthError } from "@azure/msal-common/browser"; +import { AuthErrorCodes } from "@azure/msal-common/browser"; +import { AuthErrorMessage } from "@azure/msal-common/browser"; +import { AzureCloudInstance } from "@azure/msal-common/browser"; +import { AzureCloudOptions } from "@azure/msal-common/browser"; +import { ClientAuthError } from "@azure/msal-common/browser"; +import { ClientAuthErrorCodes } from "@azure/msal-common/browser"; +import { ClientAuthErrorMessage } from "@azure/msal-common/browser"; +import { ClientConfigurationError } from "@azure/msal-common/browser"; +import { ClientConfigurationErrorCodes } from "@azure/msal-common/browser"; +import { ClientConfigurationErrorMessage } from "@azure/msal-common/browser"; +import { CommonAuthorizationCodeRequest } from "@azure/msal-common/browser"; +import { CommonAuthorizationUrlRequest } from "@azure/msal-common/browser"; +import { CommonEndSessionRequest } from "@azure/msal-common/browser"; +import { CommonSilentFlowRequest } from "@azure/msal-common/browser"; +import { ExternalTokenResponse } from "@azure/msal-common/browser"; +import { IdTokenClaims } from "@azure/msal-common/browser"; +import { ILoggerCallback } from "@azure/msal-common/browser"; +import { INetworkModule } from "@azure/msal-common/browser"; +import { InProgressPerformanceEvent } from "@azure/msal-common/browser"; +import { InteractionRequiredAuthError } from "@azure/msal-common/browser"; +import { InteractionRequiredAuthErrorCodes } from "@azure/msal-common/browser"; +import { InteractionRequiredAuthErrorMessage } from "@azure/msal-common/browser"; +import { invoke } from "@azure/msal-common/browser"; +import { invokeAsync } from "@azure/msal-common/browser"; +import { IPerformanceClient } from "@azure/msal-common/browser"; +import { IPerformanceMeasurement } from "@azure/msal-common/browser"; +import { JsonWebTokenTypes } from "@azure/msal-common/browser"; +import { Logger } from "@azure/msal-common/browser"; +import { LoggerOptions } from "@azure/msal-common/browser"; +import { LogLevel } from "@azure/msal-common/browser"; +import { NetworkRequestOptions } from "@azure/msal-common/browser"; +import { NetworkResponse } from "@azure/msal-common/browser"; +import { OIDC_DEFAULT_SCOPES } from "@azure/msal-common/browser"; +import { OIDCOptions } from "@azure/msal-common/browser"; +import { PerformanceCallbackFunction } from "@azure/msal-common/browser"; +import { PerformanceClient } from "@azure/msal-common/browser"; +import { PerformanceEvent } from "@azure/msal-common/browser"; +import { PerformanceEvents } from "@azure/msal-common/browser"; +import { PromptValue } from "@azure/msal-common/browser"; +import { ProtocolMode } from "@azure/msal-common/browser"; +import { ServerError } from "@azure/msal-common/browser"; +import { ServerResponseType } from "@azure/msal-common/browser"; +import { SignedHttpRequestParameters } from "@azure/msal-common/browser"; +import { StringDict } from "@azure/msal-common/browser"; +import { StringUtils } from "@azure/msal-common/browser"; +import { StubPerformanceClient } from "@azure/msal-common/browser"; +import { SubMeasurement } from "@azure/msal-common/browser"; +import { SystemOptions } from "@azure/msal-common/browser"; +import { TenantProfile } from "@azure/msal-common/browser"; +import { UrlString } from "@azure/msal-common/browser"; + +export { AccountEntity }; + +export { AccountInfo }; // Warning: (ae-missing-release-tag) "ApiId" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "ApiId" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -89,14 +88,15 @@ export type ApiId = (typeof ApiId)[keyof typeof ApiId]; // Warning: (ae-missing-release-tag) "authCodeOrNativeAccountIdRequired" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const authCodeOrNativeAccountIdRequired = "auth_code_or_nativeAccountId_required"; +const authCodeOrNativeAccountIdRequired = + "auth_code_or_nativeAccountId_required"; // Warning: (ae-missing-release-tag) "authCodeRequired" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const authCodeRequired = "auth_code_required"; -export { AuthenticationHeaderParser } +export { AuthenticationHeaderParser }; // Warning: (ae-missing-release-tag) "AuthenticationResult" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -105,18 +105,23 @@ export type AuthenticationResult = AuthenticationResult_2 & { account: AccountInfo; }; -export { AuthenticationScheme } +export { AuthenticationScheme }; -export { AuthError } +export { AuthError }; -export { AuthErrorCodes } +export { AuthErrorCodes }; -export { AuthErrorMessage } +export { AuthErrorMessage }; // Warning: (ae-missing-release-tag) "AuthorizationCodeRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type AuthorizationCodeRequest = Partial> & { +export type AuthorizationCodeRequest = Partial< + Omit< + CommonAuthorizationCodeRequest, + "code" | "enableSpaAuthorizationCode" | "requestedClaimsHash" + > +> & { code?: string; nativeAccountId?: string; cloudGraphHostName?: string; @@ -127,16 +132,19 @@ export type AuthorizationCodeRequest = Partial; +export type AuthorizationUrlRequest = Omit< + CommonAuthorizationUrlRequest, + "requestedClaimsHash" | "platformBroker" +>; // Warning: (ae-missing-release-tag) "authRequestNotSetError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const authRequestNotSetError = "auth_request_not_set_error"; -export { AzureCloudInstance } +export { AzureCloudInstance }; -export { AzureCloudOptions } +export { AzureCloudOptions }; // Warning: (ae-missing-release-tag) "blockAcquireTokenInPopups" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -235,10 +243,10 @@ declare namespace BrowserAuthErrorCodes { invalidPopTokenRequest, failedToBuildHeaders, failedToParseHeaders, - failedToDecryptEarResponse - } + failedToDecryptEarResponse, + }; } -export { BrowserAuthErrorCodes } +export { BrowserAuthErrorCodes }; // Warning: (ae-missing-release-tag) "BrowserAuthErrorMessage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -460,7 +468,8 @@ export const BrowserCacheLocation: { }; // @public (undocumented) -export type BrowserCacheLocation = (typeof BrowserCacheLocation)[keyof typeof BrowserCacheLocation]; +export type BrowserCacheLocation = + (typeof BrowserCacheLocation)[keyof typeof BrowserCacheLocation]; // Warning: (ae-internal-missing-underscore) The name "BrowserConfiguration" should be prefixed with an underscore because the declaration is marked as @internal // @@ -483,10 +492,10 @@ declare namespace BrowserConfigurationAuthErrorCodes { export { storageNotSupported, stubbedPublicClientApplicationCalled, - inMemRedirectUnavailable - } + inMemRedirectUnavailable, + }; } -export { BrowserConfigurationAuthErrorCodes } +export { BrowserConfigurationAuthErrorCodes }; // Warning: (ae-missing-release-tag) "BrowserConfigurationAuthErrorMessage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -509,8 +518,15 @@ export const BrowserConfigurationAuthErrorMessage: { // Warning: (ae-missing-release-tag) "BrowserPerformanceClient" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class BrowserPerformanceClient extends PerformanceClient implements IPerformanceClient { - constructor(configuration: Configuration, intFields?: Set, abbreviations?: Map); +export class BrowserPerformanceClient + extends PerformanceClient + implements IPerformanceClient +{ + constructor( + configuration: Configuration, + intFields?: Set, + abbreviations?: Map + ); // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -518,7 +534,12 @@ export class BrowserPerformanceClient extends PerformanceClient implements IPerf // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' - addQueueMeasurement(eventName: string, correlationId?: string, queueTime?: number, manuallyCompleted?: boolean): void; + addQueueMeasurement( + eventName: string, + correlationId?: string, + queueTime?: number, + manuallyCompleted?: boolean + ): void; // (undocumented) generateId(): string; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -534,7 +555,10 @@ export class BrowserPerformanceClient extends PerformanceClient implements IPerf // Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" - startMeasurement(measureName: string, correlationId?: string): InProgressPerformanceEvent; + startMeasurement( + measureName: string, + correlationId?: string + ): InProgressPerformanceEvent; } // Warning: (ae-missing-release-tag) "BrowserPerformanceMeasurement" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -550,7 +574,10 @@ export class BrowserPerformanceMeasurement implements IPerformanceMeasurement { // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' - static flushMeasurements(correlationId: string, measurements: SubMeasurement[]): void; + static flushMeasurements( + correlationId: string, + measurements: SubMeasurement[] + ): void; // (undocumented) startMeasurement(): void; // (undocumented) @@ -602,10 +629,10 @@ declare namespace BrowserUtils { preconnect, createGuid, invoke, - invokeAsync - } + invokeAsync, + }; } -export { BrowserUtils } +export { BrowserUtils }; // Warning: (ae-missing-release-tag) "CacheLookupPolicy" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "CacheLookupPolicy" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -621,7 +648,8 @@ export const CacheLookupPolicy: { }; // @public (undocumented) -export type CacheLookupPolicy = (typeof CacheLookupPolicy)[keyof typeof CacheLookupPolicy]; +export type CacheLookupPolicy = + (typeof CacheLookupPolicy)[keyof typeof CacheLookupPolicy]; // Warning: (ae-missing-release-tag) "CacheOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -648,17 +676,17 @@ export type ClearCacheRequest = { // @public function clearHash(contentWindow: Window): void; -export { ClientAuthError } +export { ClientAuthError }; -export { ClientAuthErrorCodes } +export { ClientAuthErrorCodes }; -export { ClientAuthErrorMessage } +export { ClientAuthErrorMessage }; -export { ClientConfigurationError } +export { ClientConfigurationError }; -export { ClientConfigurationErrorCodes } +export { ClientConfigurationErrorCodes }; -export { ClientConfigurationErrorMessage } +export { ClientConfigurationErrorMessage }; // Warning: (ae-missing-release-tag) "Configuration" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -681,13 +709,17 @@ function createGuid(): string; // Warning: (ae-missing-release-tag) "createNestablePublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createNestablePublicClientApplication(configuration: Configuration): Promise; +export function createNestablePublicClientApplication( + configuration: Configuration +): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (ae-missing-release-tag) "createStandardPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createStandardPublicClientApplication(configuration: Configuration): Promise; +export function createStandardPublicClientApplication( + configuration: Configuration +): Promise; // Warning: (ae-missing-release-tag) "cryptoKeyNotFound" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -737,7 +769,9 @@ const emptyWindowError = "empty_window_error"; // Warning: (ae-missing-release-tag) "EndSessionPopupRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type EndSessionPopupRequest = Partial> & { +export type EndSessionPopupRequest = Partial< + Omit +> & { authority?: string; mainWindowRedirectUri?: string; popupWindowAttributes?: PopupWindowAttributes; @@ -747,7 +781,9 @@ export type EndSessionPopupRequest = Partial> & { +export type EndSessionRequest = Partial< + Omit +> & { authority?: string; onRedirectNavigate?: (url: string) => boolean | void; }; @@ -767,12 +803,21 @@ export type EventError = AuthError | Error | null; // @public (undocumented) export class EventHandler { constructor(logger?: Logger); - addEventCallback(callback: EventCallbackFunction, eventTypes?: Array, callbackId?: string): string | null; + addEventCallback( + callback: EventCallbackFunction, + eventTypes?: Array, + callbackId?: string + ): string | null; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - emitEvent(eventType: EventType, interactionType?: InteractionType, payload?: EventPayload, error?: EventError): void; + emitEvent( + eventType: EventType, + interactionType?: InteractionType, + payload?: EventPayload, + error?: EventError + ): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen removeEventCallback(callbackId: string): void; subscribeCrossTab(): void; @@ -796,13 +841,25 @@ export type EventMessage = { export class EventMessageUtils { // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - static getInteractionStatusFromEvent(message: EventMessage, currentStatus?: InteractionStatus): InteractionStatus | null; + static getInteractionStatusFromEvent( + message: EventMessage, + currentStatus?: InteractionStatus + ): InteractionStatus | null; } // Warning: (ae-missing-release-tag) "EventPayload" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type EventPayload = AccountInfo | PopupRequest | RedirectRequest | SilentRequest | SsoSilentRequest | EndSessionRequest | AuthenticationResult | PopupEvent | null; +export type EventPayload = + | AccountInfo + | PopupRequest + | RedirectRequest + | SilentRequest + | SsoSilentRequest + | EndSessionRequest + | AuthenticationResult + | PopupEvent + | null; // Warning: (ae-missing-release-tag) "EventType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "EventType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -840,7 +897,7 @@ export const EventType: { // @public (undocumented) export type EventType = (typeof EventType)[keyof typeof EventType]; -export { ExternalTokenResponse } +export { ExternalTokenResponse }; // Warning: (ae-missing-release-tag) "failedToBuildHeaders" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -880,7 +937,8 @@ const getRequestFailed = "get_request_failed"; // Warning: (ae-missing-release-tag) "hashDoesNotContainKnownProperties" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const hashDoesNotContainKnownProperties = "hash_does_not_contain_known_properties"; +const hashDoesNotContainKnownProperties = + "hash_does_not_contain_known_properties"; // Warning: (ae-missing-release-tag) "hashEmptyError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -892,17 +950,28 @@ const hashEmptyError = "hash_empty_error"; // @public (undocumented) export interface IController { // (undocumented) - acquireTokenByCode(request: AuthorizationCodeRequest): Promise; + acquireTokenByCode( + request: AuthorizationCodeRequest + ): Promise; // (undocumented) - acquireTokenNative(request: PopupRequest | SilentRequest | SsoSilentRequest, apiId: ApiId, accountId?: string): Promise; + acquireTokenNative( + request: PopupRequest | SilentRequest | SsoSilentRequest, + apiId: ApiId, + accountId?: string + ): Promise; // (undocumented) acquireTokenPopup(request: PopupRequest): Promise; // (undocumented) acquireTokenRedirect(request: RedirectRequest): Promise; // (undocumented) - acquireTokenSilent(silentRequest: SilentRequest): Promise; + acquireTokenSilent( + silentRequest: SilentRequest + ): Promise; // (undocumented) - addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; + addEventCallback( + callback: EventCallbackFunction, + eventTypes?: Array + ): string | null; // (undocumented) addPerformanceCallback(callback: PerformanceCallbackFunction): string; // (undocumented) @@ -934,9 +1003,19 @@ export interface IController { // (undocumented) handleRedirectPromise(hash?: string): Promise; // (undocumented) - hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; + hydrateCache( + result: AuthenticationResult, + request: + | SilentRequest + | SsoSilentRequest + | RedirectRequest + | PopupRequest + ): Promise; // (undocumented) - initialize(request?: InitializeApplicationRequest, isBroker?: boolean): Promise; + initialize( + request?: InitializeApplicationRequest, + isBroker?: boolean + ): Promise; // (undocumented) initializeWrapperLibrary(sku: WrapperSKU, version: string): void; // @internal (undocumented) @@ -965,14 +1044,14 @@ export interface IController { ssoSilent(request: SsoSilentRequest): Promise; } -export { IdTokenClaims } +export { IdTokenClaims }; // Warning: (ae-missing-release-tag) "iframeClosedPrematurely" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const iframeClosedPrematurely = "iframe_closed_prematurely"; -export { ILoggerCallback } +export { ILoggerCallback }; // Warning: (ae-missing-release-tag) "INavigationClient" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -986,7 +1065,7 @@ export interface INavigationClient { navigateInternal(url: string, options: NavigationOptions): Promise; } -export { INetworkModule } +export { INetworkModule }; // Warning: (ae-missing-release-tag) "InitializeApplicationRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1000,18 +1079,18 @@ export type InitializeApplicationRequest = { // @public (undocumented) const inMemRedirectUnavailable = "in_mem_redirect_unavailable"; -export { InProgressPerformanceEvent } +export { InProgressPerformanceEvent }; // Warning: (ae-missing-release-tag) "interactionInProgress" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const interactionInProgress = "interaction_in_progress"; -export { InteractionRequiredAuthError } +export { InteractionRequiredAuthError }; -export { InteractionRequiredAuthErrorCodes } +export { InteractionRequiredAuthErrorCodes }; -export { InteractionRequiredAuthErrorMessage } +export { InteractionRequiredAuthErrorMessage }; // Warning: (ae-missing-release-tag) "InteractionStatus" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "InteractionStatus" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1028,7 +1107,8 @@ export const InteractionStatus: { }; // @public (undocumented) -export type InteractionStatus = (typeof InteractionStatus)[keyof typeof InteractionStatus]; +export type InteractionStatus = + (typeof InteractionStatus)[keyof typeof InteractionStatus]; // Warning: (ae-missing-release-tag) "InteractionType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1041,7 +1121,7 @@ export enum InteractionType { // (undocumented) Redirect = "redirect", // (undocumented) - Silent = "silent" + Silent = "silent", } // Warning: (ae-missing-release-tag) "invalidBase64String" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1059,22 +1139,29 @@ const invalidCacheType = "invalid_cache_type"; // @public (undocumented) const invalidPopTokenRequest = "invalid_pop_token_request"; -export { IPerformanceClient } +export { IPerformanceClient }; // Warning: (ae-missing-release-tag) "IPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export interface IPublicClientApplication { // (undocumented) - acquireTokenByCode(request: AuthorizationCodeRequest): Promise; + acquireTokenByCode( + request: AuthorizationCodeRequest + ): Promise; // (undocumented) acquireTokenPopup(request: PopupRequest): Promise; // (undocumented) acquireTokenRedirect(request: RedirectRequest): Promise; // (undocumented) - acquireTokenSilent(silentRequest: SilentRequest): Promise; + acquireTokenSilent( + silentRequest: SilentRequest + ): Promise; // (undocumented) - addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; + addEventCallback( + callback: EventCallbackFunction, + eventTypes?: Array + ): string | null; // (undocumented) addPerformanceCallback(callback: PerformanceCallbackFunction): string; // (undocumented) @@ -1104,7 +1191,14 @@ export interface IPublicClientApplication { // (undocumented) handleRedirectPromise(hash?: string): Promise; // (undocumented) - hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; + hydrateCache( + result: AuthenticationResult, + request: + | SilentRequest + | SsoSilentRequest + | RedirectRequest + | PopupRequest + ): Promise; // (undocumented) initialize(request?: InitializeApplicationRequest): Promise; // (undocumented) @@ -1143,11 +1237,26 @@ function isInIframe(): boolean; // @public function isInPopup(): boolean; +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// Warning: (ae-missing-release-tag) "isPlatformBrokerAvailable" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export function isPlatformBrokerAvailable( + loggerOptions?: LoggerOptions, + perfClient?: IPerformanceClient, + correlationId?: string +): Promise; + // Warning: (ae-missing-release-tag) "ITokenCache" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export interface ITokenCache { - loadExternalTokens(request: SilentRequest, response: ExternalTokenResponse, options: LoadTokenOptions): Promise; + loadExternalTokens( + request: SilentRequest, + response: ExternalTokenResponse, + options: LoadTokenOptions + ): Promise; } // Warning: (ae-missing-release-tag) "IWindowStorage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1169,7 +1278,7 @@ export interface IWindowStorage { setUserData(key: string, value: T, correlationId: string): Promise; } -export { JsonWebTokenTypes } +export { JsonWebTokenTypes }; // Warning: (ae-missing-release-tag) "LoadTokenOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1184,7 +1293,11 @@ export type LoadTokenOptions = { // // @public (undocumented) export class LocalStorage implements IWindowStorage { - constructor(clientId: string, logger: Logger, performanceClient: IPerformanceClient); + constructor( + clientId: string, + logger: Logger, + performanceClient: IPerformanceClient + ); clear(): void; // (undocumented) containsKey(key: string): boolean; @@ -1201,12 +1314,16 @@ export class LocalStorage implements IWindowStorage { // (undocumented) setItem(key: string, value: string): void; // (undocumented) - setUserData(key: string, value: string, correlationId: string): Promise; + setUserData( + key: string, + value: string, + correlationId: string + ): Promise; } -export { Logger } +export { Logger }; -export { LogLevel } +export { LogLevel }; // Warning: (ae-missing-release-tag) "MemoryStorage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1284,9 +1401,9 @@ export type NavigationOptions = { noHistory: boolean; }; -export { NetworkRequestOptions } +export { NetworkRequestOptions }; -export { NetworkResponse } +export { NetworkResponse }; // Warning: (ae-missing-release-tag) "noAccountError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1313,13 +1430,13 @@ const noStateInHash = "no_state_in_hash"; // @public (undocumented) const noTokenRequestCacheError = "no_token_request_cache_error"; -export { OIDC_DEFAULT_SCOPES } +export { OIDC_DEFAULT_SCOPES }; -export { PerformanceCallbackFunction } +export { PerformanceCallbackFunction }; -export { PerformanceEvent } +export { PerformanceEvent }; -export { PerformanceEvents } +export { PerformanceEvents }; // Warning: (ae-missing-release-tag) "pkceNotCreated" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1344,7 +1461,18 @@ export type PopupPosition = { // Warning: (ae-missing-release-tag) "PopupRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type PopupRequest = Partial> & { +export type PopupRequest = Partial< + Omit< + CommonAuthorizationUrlRequest, + | "responseMode" + | "scopes" + | "earJwk" + | "codeChallenge" + | "codeChallengeMethod" + | "requestedClaimsHash" + | "platformBroker" + > +> & { scopes: Array; popupWindowAttributes?: PopupWindowAttributes; popupWindowParent?: Window; @@ -1388,9 +1516,9 @@ function preconnect(authority: string): void; // @public function preflightCheck(initialized: boolean): void; -export { PromptValue } +export { PromptValue }; -export { ProtocolMode } +export { ProtocolMode }; // Warning: (ae-missing-release-tag) "PublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1409,7 +1537,9 @@ export class PublicClientApplication implements IPublicClientApplication { // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen constructor(configuration: Configuration, controller?: IController); // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - acquireTokenByCode(request: AuthorizationCodeRequest): Promise; + acquireTokenByCode( + request: AuthorizationCodeRequest + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen acquireTokenPopup(request: PopupRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1417,10 +1547,15 @@ export class PublicClientApplication implements IPublicClientApplication { // Warning: (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a parameter name // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" - acquireTokenSilent(silentRequest: SilentRequest): Promise; + acquireTokenSilent( + silentRequest: SilentRequest + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; + addEventCallback( + callback: EventCallbackFunction, + eventTypes?: Array + ): string | null; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag @@ -1432,7 +1567,9 @@ export class PublicClientApplication implements IPublicClientApplication { protected controller: IController; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' - static createPublicClientApplication(configuration: Configuration): Promise; + static createPublicClientApplication( + configuration: Configuration + ): Promise; disableAccountStorageEvents(): void; enableAccountStorageEvents(): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1456,9 +1593,18 @@ export class PublicClientApplication implements IPublicClientApplication { getLogger(): Logger; getTokenCache(): ITokenCache; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - handleRedirectPromise(hash?: string | undefined): Promise; + handleRedirectPromise( + hash?: string | undefined + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; + hydrateCache( + result: AuthenticationResult, + request: + | SilentRequest + | SsoSilentRequest + | RedirectRequest + | PopupRequest + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' initialize(request?: InitializeApplicationRequest): Promise; @@ -1468,7 +1614,9 @@ export class PublicClientApplication implements IPublicClientApplication { // (undocumented) protected isBroker: boolean; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - loginPopup(request?: PopupRequest | undefined): Promise; + loginPopup( + request?: PopupRequest | undefined + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen loginRedirect(request?: RedirectRequest | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1502,7 +1650,9 @@ export class PublicClientApplication implements IPublicClientApplication { // @public export class PublicClientNext implements IPublicClientApplication { // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - acquireTokenByCode(request: AuthorizationCodeRequest): Promise; + acquireTokenByCode( + request: AuthorizationCodeRequest + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen acquireTokenPopup(request: PopupRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1510,9 +1660,14 @@ export class PublicClientNext implements IPublicClientApplication { // Warning: (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a parameter name // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" - acquireTokenSilent(silentRequest: SilentRequest): Promise; + acquireTokenSilent( + silentRequest: SilentRequest + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; + addEventCallback( + callback: EventCallbackFunction, + eventTypes?: Array + ): string | null; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag @@ -1525,7 +1680,9 @@ export class PublicClientNext implements IPublicClientApplication { // (undocumented) protected controller: IController; // (undocumented) - static createPublicClientApplication(configuration: Configuration): Promise; + static createPublicClientApplication( + configuration: Configuration + ): Promise; disableAccountStorageEvents(): void; enableAccountStorageEvents(): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1549,15 +1706,26 @@ export class PublicClientNext implements IPublicClientApplication { getLogger(): Logger; getTokenCache(): ITokenCache; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - handleRedirectPromise(hash?: string | undefined): Promise; - // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; + handleRedirectPromise( + hash?: string | undefined + ): Promise; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + hydrateCache( + result: AuthenticationResult, + request: + | SilentRequest + | SsoSilentRequest + | RedirectRequest + | PopupRequest + ): Promise; initialize(): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen initializeWrapperLibrary(sku: WrapperSKU, version: string): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - loginPopup(request?: PopupRequest | undefined): Promise; + loginPopup( + request?: PopupRequest | undefined + ): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen loginRedirect(request?: RedirectRequest | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1598,12 +1766,26 @@ const redirectInIframe = "redirect_in_iframe"; // Warning: (ae-missing-release-tag) "redirectPreflightCheck" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -function redirectPreflightCheck(initialized: boolean, config: BrowserConfiguration): void; +function redirectPreflightCheck( + initialized: boolean, + config: BrowserConfiguration +): void; // Warning: (ae-missing-release-tag) "RedirectRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type RedirectRequest = Partial> & { +export type RedirectRequest = Partial< + Omit< + CommonAuthorizationUrlRequest, + | "responseMode" + | "scopes" + | "earJwk" + | "codeChallenge" + | "codeChallengeMethod" + | "requestedClaimsHash" + | "platformBroker" + > +> & { scopes: Array; redirectStartPage?: string; onRedirectNavigate?: (url: string) => boolean | void; @@ -1614,9 +1796,9 @@ export type RedirectRequest = Partial { // // @public (undocumented) export class SignedHttpRequest { - constructor(shrParameters: SignedHttpRequestParameters, shrOptions?: SignedHttpRequestOptions); + constructor( + shrParameters: SignedHttpRequestParameters, + shrOptions?: SignedHttpRequestOptions + ); generatePublicKeyThumbprint(): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen removeKeys(publicKeyThumbprint: string): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - signRequest(payload: string, publicKeyThumbprint: string, claims?: object): Promise; + signRequest( + payload: string, + publicKeyThumbprint: string, + claims?: object + ): Promise; } // Warning: (ae-missing-release-tag) "SignedHttpRequestOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1675,7 +1864,14 @@ const silentPromptValueError = "silent_prompt_value_error"; // Warning: (ae-missing-release-tag) "SilentRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type SilentRequest = Omit & { +export type SilentRequest = Omit< + CommonSilentFlowRequest, + | "authority" + | "correlationId" + | "forceRefresh" + | "account" + | "requestedClaimsHash" +> & { redirectUri?: string; extraQueryParameters?: StringDict; authority?: string; @@ -1695,7 +1891,17 @@ const spaCodeAndNativeAccountIdPresent = "spa_code_and_nativeAccountId_present"; // Warning: (ae-missing-release-tag) "SsoSilentRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type SsoSilentRequest = Partial>; +export type SsoSilentRequest = Partial< + Omit< + CommonAuthorizationUrlRequest, + | "responseMode" + | "earJwk" + | "codeChallenge" + | "codeChallengeMethod" + | "requestedClaimsHash" + | "platformBroker" + > +>; // Warning: (ae-missing-release-tag) "stateInteractionTypeMismatch" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1707,7 +1913,7 @@ const stateInteractionTypeMismatch = "state_interaction_type_mismatch"; // @public (undocumented) const storageNotSupported = "storage_not_supported"; -export { StringUtils } +export { StringUtils }; // Warning: (ae-missing-release-tag) "stubbedPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1717,16 +1923,18 @@ export const stubbedPublicClientApplication: IPublicClientApplication; // Warning: (ae-missing-release-tag) "stubbedPublicClientApplicationCalled" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const stubbedPublicClientApplicationCalled = "stubbed_public_client_application_called"; +const stubbedPublicClientApplicationCalled = + "stubbed_public_client_application_called"; -export { StubPerformanceClient } +export { StubPerformanceClient }; -export { TenantProfile } +export { TenantProfile }; // Warning: (ae-missing-release-tag) "unableToAcquireTokenFromNativePlatform" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const unableToAcquireTokenFromNativePlatform = "unable_to_acquire_token_from_native_platform"; +const unableToAcquireTokenFromNativePlatform = + "unable_to_acquire_token_from_native_platform"; // Warning: (ae-missing-release-tag) "unableToLoadToken" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1741,14 +1949,16 @@ const unableToParseState = "unable_to_parse_state"; // Warning: (ae-missing-release-tag) "unableToParseTokenRequestCacheError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const unableToParseTokenRequestCacheError = "unable_to_parse_token_request_cache_error"; +const unableToParseTokenRequestCacheError = + "unable_to_parse_token_request_cache_error"; // Warning: (ae-missing-release-tag) "uninitializedPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const uninitializedPublicClientApplication = "uninitialized_public_client_application"; +const uninitializedPublicClientApplication = + "uninitialized_public_client_application"; -export { UrlString } +export { UrlString }; // Warning: (ae-missing-release-tag) "userCancelled" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1795,5 +2005,4 @@ export type WrapperSKU = (typeof WrapperSKU)[keyof typeof WrapperSKU]; // src/index.ts:8:4 - (tsdoc-undefined-tag) The TSDoc tag "@module" is not defined in this configuration // src/navigation/NavigationClient.ts:36:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // src/navigation/NavigationClient.ts:37:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - ``` From bcb22a58154eea1c15c9fccaaea49a74a30f55b6 Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Mon, 12 May 2025 16:40:34 -0700 Subject: [PATCH 29/30] undoing prettier formatting changes --- .../apiReview/msal-browser.api.md | 548 ++++++------------ 1 file changed, 173 insertions(+), 375 deletions(-) diff --git a/lib/msal-browser/apiReview/msal-browser.api.md b/lib/msal-browser/apiReview/msal-browser.api.md index 8c626421a5..c28d15b403 100644 --- a/lib/msal-browser/apiReview/msal-browser.api.md +++ b/lib/msal-browser/apiReview/msal-browser.api.md @@ -3,68 +3,69 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AccountEntity } from "@azure/msal-common/browser"; -import { AccountFilter } from "@azure/msal-common/browser"; -import { AccountInfo } from "@azure/msal-common/browser"; -import { ApplicationTelemetry } from "@azure/msal-common/browser"; -import { AuthenticationHeaderParser } from "@azure/msal-common/browser"; -import { AuthenticationResult as AuthenticationResult_2 } from "@azure/msal-common/browser"; -import { AuthenticationScheme } from "@azure/msal-common/browser"; -import { AuthError } from "@azure/msal-common/browser"; -import { AuthErrorCodes } from "@azure/msal-common/browser"; -import { AuthErrorMessage } from "@azure/msal-common/browser"; -import { AzureCloudInstance } from "@azure/msal-common/browser"; -import { AzureCloudOptions } from "@azure/msal-common/browser"; -import { ClientAuthError } from "@azure/msal-common/browser"; -import { ClientAuthErrorCodes } from "@azure/msal-common/browser"; -import { ClientAuthErrorMessage } from "@azure/msal-common/browser"; -import { ClientConfigurationError } from "@azure/msal-common/browser"; -import { ClientConfigurationErrorCodes } from "@azure/msal-common/browser"; -import { ClientConfigurationErrorMessage } from "@azure/msal-common/browser"; -import { CommonAuthorizationCodeRequest } from "@azure/msal-common/browser"; -import { CommonAuthorizationUrlRequest } from "@azure/msal-common/browser"; -import { CommonEndSessionRequest } from "@azure/msal-common/browser"; -import { CommonSilentFlowRequest } from "@azure/msal-common/browser"; -import { ExternalTokenResponse } from "@azure/msal-common/browser"; -import { IdTokenClaims } from "@azure/msal-common/browser"; -import { ILoggerCallback } from "@azure/msal-common/browser"; -import { INetworkModule } from "@azure/msal-common/browser"; -import { InProgressPerformanceEvent } from "@azure/msal-common/browser"; -import { InteractionRequiredAuthError } from "@azure/msal-common/browser"; -import { InteractionRequiredAuthErrorCodes } from "@azure/msal-common/browser"; -import { InteractionRequiredAuthErrorMessage } from "@azure/msal-common/browser"; -import { invoke } from "@azure/msal-common/browser"; -import { invokeAsync } from "@azure/msal-common/browser"; -import { IPerformanceClient } from "@azure/msal-common/browser"; -import { IPerformanceMeasurement } from "@azure/msal-common/browser"; -import { JsonWebTokenTypes } from "@azure/msal-common/browser"; -import { Logger } from "@azure/msal-common/browser"; -import { LoggerOptions } from "@azure/msal-common/browser"; -import { LogLevel } from "@azure/msal-common/browser"; -import { NetworkRequestOptions } from "@azure/msal-common/browser"; -import { NetworkResponse } from "@azure/msal-common/browser"; -import { OIDC_DEFAULT_SCOPES } from "@azure/msal-common/browser"; -import { OIDCOptions } from "@azure/msal-common/browser"; -import { PerformanceCallbackFunction } from "@azure/msal-common/browser"; -import { PerformanceClient } from "@azure/msal-common/browser"; -import { PerformanceEvent } from "@azure/msal-common/browser"; -import { PerformanceEvents } from "@azure/msal-common/browser"; -import { PromptValue } from "@azure/msal-common/browser"; -import { ProtocolMode } from "@azure/msal-common/browser"; -import { ServerError } from "@azure/msal-common/browser"; -import { ServerResponseType } from "@azure/msal-common/browser"; -import { SignedHttpRequestParameters } from "@azure/msal-common/browser"; -import { StringDict } from "@azure/msal-common/browser"; -import { StringUtils } from "@azure/msal-common/browser"; -import { StubPerformanceClient } from "@azure/msal-common/browser"; -import { SubMeasurement } from "@azure/msal-common/browser"; -import { SystemOptions } from "@azure/msal-common/browser"; -import { TenantProfile } from "@azure/msal-common/browser"; -import { UrlString } from "@azure/msal-common/browser"; - -export { AccountEntity }; - -export { AccountInfo }; + +import { AccountEntity } from '@azure/msal-common/browser'; +import { AccountFilter } from '@azure/msal-common/browser'; +import { AccountInfo } from '@azure/msal-common/browser'; +import { ApplicationTelemetry } from '@azure/msal-common/browser'; +import { AuthenticationHeaderParser } from '@azure/msal-common/browser'; +import { AuthenticationResult as AuthenticationResult_2 } from '@azure/msal-common/browser'; +import { AuthenticationScheme } from '@azure/msal-common/browser'; +import { AuthError } from '@azure/msal-common/browser'; +import { AuthErrorCodes } from '@azure/msal-common/browser'; +import { AuthErrorMessage } from '@azure/msal-common/browser'; +import { AzureCloudInstance } from '@azure/msal-common/browser'; +import { AzureCloudOptions } from '@azure/msal-common/browser'; +import { ClientAuthError } from '@azure/msal-common/browser'; +import { ClientAuthErrorCodes } from '@azure/msal-common/browser'; +import { ClientAuthErrorMessage } from '@azure/msal-common/browser'; +import { ClientConfigurationError } from '@azure/msal-common/browser'; +import { ClientConfigurationErrorCodes } from '@azure/msal-common/browser'; +import { ClientConfigurationErrorMessage } from '@azure/msal-common/browser'; +import { CommonAuthorizationCodeRequest } from '@azure/msal-common/browser'; +import { CommonAuthorizationUrlRequest } from '@azure/msal-common/browser'; +import { CommonEndSessionRequest } from '@azure/msal-common/browser'; +import { CommonSilentFlowRequest } from '@azure/msal-common/browser'; +import { ExternalTokenResponse } from '@azure/msal-common/browser'; +import { IdTokenClaims } from '@azure/msal-common/browser'; +import { ILoggerCallback } from '@azure/msal-common/browser'; +import { INetworkModule } from '@azure/msal-common/browser'; +import { InProgressPerformanceEvent } from '@azure/msal-common/browser'; +import { InteractionRequiredAuthError } from '@azure/msal-common/browser'; +import { InteractionRequiredAuthErrorCodes } from '@azure/msal-common/browser'; +import { InteractionRequiredAuthErrorMessage } from '@azure/msal-common/browser'; +import { invoke } from '@azure/msal-common/browser'; +import { invokeAsync } from '@azure/msal-common/browser'; +import { IPerformanceClient } from '@azure/msal-common/browser'; +import { IPerformanceMeasurement } from '@azure/msal-common/browser'; +import { JsonWebTokenTypes } from '@azure/msal-common/browser'; +import { Logger } from '@azure/msal-common/browser'; +import { LoggerOptions } from '@azure/msal-common/browser'; +import { LogLevel } from '@azure/msal-common/browser'; +import { NetworkRequestOptions } from '@azure/msal-common/browser'; +import { NetworkResponse } from '@azure/msal-common/browser'; +import { OIDC_DEFAULT_SCOPES } from '@azure/msal-common/browser'; +import { OIDCOptions } from '@azure/msal-common/browser'; +import { PerformanceCallbackFunction } from '@azure/msal-common/browser'; +import { PerformanceClient } from '@azure/msal-common/browser'; +import { PerformanceEvent } from '@azure/msal-common/browser'; +import { PerformanceEvents } from '@azure/msal-common/browser'; +import { PromptValue } from '@azure/msal-common/browser'; +import { ProtocolMode } from '@azure/msal-common/browser'; +import { ServerError } from '@azure/msal-common/browser'; +import { ServerResponseType } from '@azure/msal-common/browser'; +import { SignedHttpRequestParameters } from '@azure/msal-common/browser'; +import { StringDict } from '@azure/msal-common/browser'; +import { StringUtils } from '@azure/msal-common/browser'; +import { StubPerformanceClient } from '@azure/msal-common/browser'; +import { SubMeasurement } from '@azure/msal-common/browser'; +import { SystemOptions } from '@azure/msal-common/browser'; +import { TenantProfile } from '@azure/msal-common/browser'; +import { UrlString } from '@azure/msal-common/browser'; + +export { AccountEntity } + +export { AccountInfo } // Warning: (ae-missing-release-tag) "ApiId" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "ApiId" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -88,15 +89,14 @@ export type ApiId = (typeof ApiId)[keyof typeof ApiId]; // Warning: (ae-missing-release-tag) "authCodeOrNativeAccountIdRequired" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const authCodeOrNativeAccountIdRequired = - "auth_code_or_nativeAccountId_required"; +const authCodeOrNativeAccountIdRequired = "auth_code_or_nativeAccountId_required"; // Warning: (ae-missing-release-tag) "authCodeRequired" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const authCodeRequired = "auth_code_required"; -export { AuthenticationHeaderParser }; +export { AuthenticationHeaderParser } // Warning: (ae-missing-release-tag) "AuthenticationResult" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -105,23 +105,18 @@ export type AuthenticationResult = AuthenticationResult_2 & { account: AccountInfo; }; -export { AuthenticationScheme }; +export { AuthenticationScheme } -export { AuthError }; +export { AuthError } -export { AuthErrorCodes }; +export { AuthErrorCodes } -export { AuthErrorMessage }; +export { AuthErrorMessage } // Warning: (ae-missing-release-tag) "AuthorizationCodeRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type AuthorizationCodeRequest = Partial< - Omit< - CommonAuthorizationCodeRequest, - "code" | "enableSpaAuthorizationCode" | "requestedClaimsHash" - > -> & { +export type AuthorizationCodeRequest = Partial> & { code?: string; nativeAccountId?: string; cloudGraphHostName?: string; @@ -132,19 +127,16 @@ export type AuthorizationCodeRequest = Partial< // Warning: (ae-missing-release-tag) "AuthorizationUrlRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @deprecated -export type AuthorizationUrlRequest = Omit< - CommonAuthorizationUrlRequest, - "requestedClaimsHash" | "platformBroker" ->; +export type AuthorizationUrlRequest = Omit; // Warning: (ae-missing-release-tag) "authRequestNotSetError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const authRequestNotSetError = "auth_request_not_set_error"; -export { AzureCloudInstance }; +export { AzureCloudInstance } -export { AzureCloudOptions }; +export { AzureCloudOptions } // Warning: (ae-missing-release-tag) "blockAcquireTokenInPopups" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -243,10 +235,10 @@ declare namespace BrowserAuthErrorCodes { invalidPopTokenRequest, failedToBuildHeaders, failedToParseHeaders, - failedToDecryptEarResponse, - }; + failedToDecryptEarResponse + } } -export { BrowserAuthErrorCodes }; +export { BrowserAuthErrorCodes } // Warning: (ae-missing-release-tag) "BrowserAuthErrorMessage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -468,8 +460,7 @@ export const BrowserCacheLocation: { }; // @public (undocumented) -export type BrowserCacheLocation = - (typeof BrowserCacheLocation)[keyof typeof BrowserCacheLocation]; +export type BrowserCacheLocation = (typeof BrowserCacheLocation)[keyof typeof BrowserCacheLocation]; // Warning: (ae-internal-missing-underscore) The name "BrowserConfiguration" should be prefixed with an underscore because the declaration is marked as @internal // @@ -492,10 +483,10 @@ declare namespace BrowserConfigurationAuthErrorCodes { export { storageNotSupported, stubbedPublicClientApplicationCalled, - inMemRedirectUnavailable, - }; + inMemRedirectUnavailable + } } -export { BrowserConfigurationAuthErrorCodes }; +export { BrowserConfigurationAuthErrorCodes } // Warning: (ae-missing-release-tag) "BrowserConfigurationAuthErrorMessage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -518,15 +509,8 @@ export const BrowserConfigurationAuthErrorMessage: { // Warning: (ae-missing-release-tag) "BrowserPerformanceClient" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class BrowserPerformanceClient - extends PerformanceClient - implements IPerformanceClient -{ - constructor( - configuration: Configuration, - intFields?: Set, - abbreviations?: Map - ); +export class BrowserPerformanceClient extends PerformanceClient implements IPerformanceClient { + constructor(configuration: Configuration, intFields?: Set, abbreviations?: Map); // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -534,12 +518,7 @@ export class BrowserPerformanceClient // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' - addQueueMeasurement( - eventName: string, - correlationId?: string, - queueTime?: number, - manuallyCompleted?: boolean - ): void; + addQueueMeasurement(eventName: string, correlationId?: string, queueTime?: number, manuallyCompleted?: boolean): void; // (undocumented) generateId(): string; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -555,10 +534,7 @@ export class BrowserPerformanceClient // Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" - startMeasurement( - measureName: string, - correlationId?: string - ): InProgressPerformanceEvent; + startMeasurement(measureName: string, correlationId?: string): InProgressPerformanceEvent; } // Warning: (ae-missing-release-tag) "BrowserPerformanceMeasurement" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -574,10 +550,7 @@ export class BrowserPerformanceMeasurement implements IPerformanceMeasurement { // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' - static flushMeasurements( - correlationId: string, - measurements: SubMeasurement[] - ): void; + static flushMeasurements(correlationId: string, measurements: SubMeasurement[]): void; // (undocumented) startMeasurement(): void; // (undocumented) @@ -629,10 +602,10 @@ declare namespace BrowserUtils { preconnect, createGuid, invoke, - invokeAsync, - }; + invokeAsync + } } -export { BrowserUtils }; +export { BrowserUtils } // Warning: (ae-missing-release-tag) "CacheLookupPolicy" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "CacheLookupPolicy" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -648,8 +621,7 @@ export const CacheLookupPolicy: { }; // @public (undocumented) -export type CacheLookupPolicy = - (typeof CacheLookupPolicy)[keyof typeof CacheLookupPolicy]; +export type CacheLookupPolicy = (typeof CacheLookupPolicy)[keyof typeof CacheLookupPolicy]; // Warning: (ae-missing-release-tag) "CacheOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -676,17 +648,17 @@ export type ClearCacheRequest = { // @public function clearHash(contentWindow: Window): void; -export { ClientAuthError }; +export { ClientAuthError } -export { ClientAuthErrorCodes }; +export { ClientAuthErrorCodes } -export { ClientAuthErrorMessage }; +export { ClientAuthErrorMessage } -export { ClientConfigurationError }; +export { ClientConfigurationError } -export { ClientConfigurationErrorCodes }; +export { ClientConfigurationErrorCodes } -export { ClientConfigurationErrorMessage }; +export { ClientConfigurationErrorMessage } // Warning: (ae-missing-release-tag) "Configuration" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -709,17 +681,13 @@ function createGuid(): string; // Warning: (ae-missing-release-tag) "createNestablePublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createNestablePublicClientApplication( - configuration: Configuration -): Promise; +export function createNestablePublicClientApplication(configuration: Configuration): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (ae-missing-release-tag) "createStandardPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createStandardPublicClientApplication( - configuration: Configuration -): Promise; +export function createStandardPublicClientApplication(configuration: Configuration): Promise; // Warning: (ae-missing-release-tag) "cryptoKeyNotFound" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -769,9 +737,7 @@ const emptyWindowError = "empty_window_error"; // Warning: (ae-missing-release-tag) "EndSessionPopupRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type EndSessionPopupRequest = Partial< - Omit -> & { +export type EndSessionPopupRequest = Partial> & { authority?: string; mainWindowRedirectUri?: string; popupWindowAttributes?: PopupWindowAttributes; @@ -781,9 +747,7 @@ export type EndSessionPopupRequest = Partial< // Warning: (ae-missing-release-tag) "EndSessionRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type EndSessionRequest = Partial< - Omit -> & { +export type EndSessionRequest = Partial> & { authority?: string; onRedirectNavigate?: (url: string) => boolean | void; }; @@ -803,21 +767,12 @@ export type EventError = AuthError | Error | null; // @public (undocumented) export class EventHandler { constructor(logger?: Logger); - addEventCallback( - callback: EventCallbackFunction, - eventTypes?: Array, - callbackId?: string - ): string | null; + addEventCallback(callback: EventCallbackFunction, eventTypes?: Array, callbackId?: string): string | null; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - emitEvent( - eventType: EventType, - interactionType?: InteractionType, - payload?: EventPayload, - error?: EventError - ): void; + emitEvent(eventType: EventType, interactionType?: InteractionType, payload?: EventPayload, error?: EventError): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen removeEventCallback(callbackId: string): void; subscribeCrossTab(): void; @@ -841,25 +796,13 @@ export type EventMessage = { export class EventMessageUtils { // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - static getInteractionStatusFromEvent( - message: EventMessage, - currentStatus?: InteractionStatus - ): InteractionStatus | null; + static getInteractionStatusFromEvent(message: EventMessage, currentStatus?: InteractionStatus): InteractionStatus | null; } // Warning: (ae-missing-release-tag) "EventPayload" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type EventPayload = - | AccountInfo - | PopupRequest - | RedirectRequest - | SilentRequest - | SsoSilentRequest - | EndSessionRequest - | AuthenticationResult - | PopupEvent - | null; +export type EventPayload = AccountInfo | PopupRequest | RedirectRequest | SilentRequest | SsoSilentRequest | EndSessionRequest | AuthenticationResult | PopupEvent | null; // Warning: (ae-missing-release-tag) "EventType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "EventType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -897,7 +840,7 @@ export const EventType: { // @public (undocumented) export type EventType = (typeof EventType)[keyof typeof EventType]; -export { ExternalTokenResponse }; +export { ExternalTokenResponse } // Warning: (ae-missing-release-tag) "failedToBuildHeaders" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -937,8 +880,7 @@ const getRequestFailed = "get_request_failed"; // Warning: (ae-missing-release-tag) "hashDoesNotContainKnownProperties" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const hashDoesNotContainKnownProperties = - "hash_does_not_contain_known_properties"; +const hashDoesNotContainKnownProperties = "hash_does_not_contain_known_properties"; // Warning: (ae-missing-release-tag) "hashEmptyError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -950,28 +892,17 @@ const hashEmptyError = "hash_empty_error"; // @public (undocumented) export interface IController { // (undocumented) - acquireTokenByCode( - request: AuthorizationCodeRequest - ): Promise; + acquireTokenByCode(request: AuthorizationCodeRequest): Promise; // (undocumented) - acquireTokenNative( - request: PopupRequest | SilentRequest | SsoSilentRequest, - apiId: ApiId, - accountId?: string - ): Promise; + acquireTokenNative(request: PopupRequest | SilentRequest | SsoSilentRequest, apiId: ApiId, accountId?: string): Promise; // (undocumented) acquireTokenPopup(request: PopupRequest): Promise; // (undocumented) acquireTokenRedirect(request: RedirectRequest): Promise; // (undocumented) - acquireTokenSilent( - silentRequest: SilentRequest - ): Promise; + acquireTokenSilent(silentRequest: SilentRequest): Promise; // (undocumented) - addEventCallback( - callback: EventCallbackFunction, - eventTypes?: Array - ): string | null; + addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; // (undocumented) addPerformanceCallback(callback: PerformanceCallbackFunction): string; // (undocumented) @@ -1003,19 +934,9 @@ export interface IController { // (undocumented) handleRedirectPromise(hash?: string): Promise; // (undocumented) - hydrateCache( - result: AuthenticationResult, - request: - | SilentRequest - | SsoSilentRequest - | RedirectRequest - | PopupRequest - ): Promise; + hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; // (undocumented) - initialize( - request?: InitializeApplicationRequest, - isBroker?: boolean - ): Promise; + initialize(request?: InitializeApplicationRequest, isBroker?: boolean): Promise; // (undocumented) initializeWrapperLibrary(sku: WrapperSKU, version: string): void; // @internal (undocumented) @@ -1044,14 +965,14 @@ export interface IController { ssoSilent(request: SsoSilentRequest): Promise; } -export { IdTokenClaims }; +export { IdTokenClaims } // Warning: (ae-missing-release-tag) "iframeClosedPrematurely" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const iframeClosedPrematurely = "iframe_closed_prematurely"; -export { ILoggerCallback }; +export { ILoggerCallback } // Warning: (ae-missing-release-tag) "INavigationClient" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1065,7 +986,7 @@ export interface INavigationClient { navigateInternal(url: string, options: NavigationOptions): Promise; } -export { INetworkModule }; +export { INetworkModule } // Warning: (ae-missing-release-tag) "InitializeApplicationRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1079,18 +1000,18 @@ export type InitializeApplicationRequest = { // @public (undocumented) const inMemRedirectUnavailable = "in_mem_redirect_unavailable"; -export { InProgressPerformanceEvent }; +export { InProgressPerformanceEvent } // Warning: (ae-missing-release-tag) "interactionInProgress" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) const interactionInProgress = "interaction_in_progress"; -export { InteractionRequiredAuthError }; +export { InteractionRequiredAuthError } -export { InteractionRequiredAuthErrorCodes }; +export { InteractionRequiredAuthErrorCodes } -export { InteractionRequiredAuthErrorMessage }; +export { InteractionRequiredAuthErrorMessage } // Warning: (ae-missing-release-tag) "InteractionStatus" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // Warning: (ae-missing-release-tag) "InteractionStatus" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1107,8 +1028,7 @@ export const InteractionStatus: { }; // @public (undocumented) -export type InteractionStatus = - (typeof InteractionStatus)[keyof typeof InteractionStatus]; +export type InteractionStatus = (typeof InteractionStatus)[keyof typeof InteractionStatus]; // Warning: (ae-missing-release-tag) "InteractionType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1121,7 +1041,7 @@ export enum InteractionType { // (undocumented) Redirect = "redirect", // (undocumented) - Silent = "silent", + Silent = "silent" } // Warning: (ae-missing-release-tag) "invalidBase64String" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1139,29 +1059,22 @@ const invalidCacheType = "invalid_cache_type"; // @public (undocumented) const invalidPopTokenRequest = "invalid_pop_token_request"; -export { IPerformanceClient }; +export { IPerformanceClient } // Warning: (ae-missing-release-tag) "IPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export interface IPublicClientApplication { // (undocumented) - acquireTokenByCode( - request: AuthorizationCodeRequest - ): Promise; + acquireTokenByCode(request: AuthorizationCodeRequest): Promise; // (undocumented) acquireTokenPopup(request: PopupRequest): Promise; // (undocumented) acquireTokenRedirect(request: RedirectRequest): Promise; // (undocumented) - acquireTokenSilent( - silentRequest: SilentRequest - ): Promise; + acquireTokenSilent(silentRequest: SilentRequest): Promise; // (undocumented) - addEventCallback( - callback: EventCallbackFunction, - eventTypes?: Array - ): string | null; + addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; // (undocumented) addPerformanceCallback(callback: PerformanceCallbackFunction): string; // (undocumented) @@ -1191,14 +1104,7 @@ export interface IPublicClientApplication { // (undocumented) handleRedirectPromise(hash?: string): Promise; // (undocumented) - hydrateCache( - result: AuthenticationResult, - request: - | SilentRequest - | SsoSilentRequest - | RedirectRequest - | PopupRequest - ): Promise; + hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; // (undocumented) initialize(request?: InitializeApplicationRequest): Promise; // (undocumented) @@ -1242,21 +1148,13 @@ function isInPopup(): boolean; // Warning: (ae-missing-release-tag) "isPlatformBrokerAvailable" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function isPlatformBrokerAvailable( - loggerOptions?: LoggerOptions, - perfClient?: IPerformanceClient, - correlationId?: string -): Promise; +export function isPlatformBrokerAvailable(loggerOptions?: LoggerOptions, perfClient?: IPerformanceClient, correlationId?: string): Promise; // Warning: (ae-missing-release-tag) "ITokenCache" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export interface ITokenCache { - loadExternalTokens( - request: SilentRequest, - response: ExternalTokenResponse, - options: LoadTokenOptions - ): Promise; + loadExternalTokens(request: SilentRequest, response: ExternalTokenResponse, options: LoadTokenOptions): Promise; } // Warning: (ae-missing-release-tag) "IWindowStorage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1278,7 +1176,7 @@ export interface IWindowStorage { setUserData(key: string, value: T, correlationId: string): Promise; } -export { JsonWebTokenTypes }; +export { JsonWebTokenTypes } // Warning: (ae-missing-release-tag) "LoadTokenOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1293,11 +1191,7 @@ export type LoadTokenOptions = { // // @public (undocumented) export class LocalStorage implements IWindowStorage { - constructor( - clientId: string, - logger: Logger, - performanceClient: IPerformanceClient - ); + constructor(clientId: string, logger: Logger, performanceClient: IPerformanceClient); clear(): void; // (undocumented) containsKey(key: string): boolean; @@ -1314,16 +1208,12 @@ export class LocalStorage implements IWindowStorage { // (undocumented) setItem(key: string, value: string): void; // (undocumented) - setUserData( - key: string, - value: string, - correlationId: string - ): Promise; + setUserData(key: string, value: string, correlationId: string): Promise; } -export { Logger }; +export { Logger } -export { LogLevel }; +export { LogLevel } // Warning: (ae-missing-release-tag) "MemoryStorage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1401,9 +1291,9 @@ export type NavigationOptions = { noHistory: boolean; }; -export { NetworkRequestOptions }; +export { NetworkRequestOptions } -export { NetworkResponse }; +export { NetworkResponse } // Warning: (ae-missing-release-tag) "noAccountError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1430,13 +1320,13 @@ const noStateInHash = "no_state_in_hash"; // @public (undocumented) const noTokenRequestCacheError = "no_token_request_cache_error"; -export { OIDC_DEFAULT_SCOPES }; +export { OIDC_DEFAULT_SCOPES } -export { PerformanceCallbackFunction }; +export { PerformanceCallbackFunction } -export { PerformanceEvent }; +export { PerformanceEvent } -export { PerformanceEvents }; +export { PerformanceEvents } // Warning: (ae-missing-release-tag) "pkceNotCreated" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1461,18 +1351,7 @@ export type PopupPosition = { // Warning: (ae-missing-release-tag) "PopupRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type PopupRequest = Partial< - Omit< - CommonAuthorizationUrlRequest, - | "responseMode" - | "scopes" - | "earJwk" - | "codeChallenge" - | "codeChallengeMethod" - | "requestedClaimsHash" - | "platformBroker" - > -> & { +export type PopupRequest = Partial> & { scopes: Array; popupWindowAttributes?: PopupWindowAttributes; popupWindowParent?: Window; @@ -1516,9 +1395,9 @@ function preconnect(authority: string): void; // @public function preflightCheck(initialized: boolean): void; -export { PromptValue }; +export { PromptValue } -export { ProtocolMode }; +export { ProtocolMode } // Warning: (ae-missing-release-tag) "PublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1537,9 +1416,7 @@ export class PublicClientApplication implements IPublicClientApplication { // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen constructor(configuration: Configuration, controller?: IController); // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - acquireTokenByCode( - request: AuthorizationCodeRequest - ): Promise; + acquireTokenByCode(request: AuthorizationCodeRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen acquireTokenPopup(request: PopupRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1547,15 +1424,10 @@ export class PublicClientApplication implements IPublicClientApplication { // Warning: (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a parameter name // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" - acquireTokenSilent( - silentRequest: SilentRequest - ): Promise; + acquireTokenSilent(silentRequest: SilentRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - addEventCallback( - callback: EventCallbackFunction, - eventTypes?: Array - ): string | null; + addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag @@ -1567,9 +1439,7 @@ export class PublicClientApplication implements IPublicClientApplication { protected controller: IController; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' - static createPublicClientApplication( - configuration: Configuration - ): Promise; + static createPublicClientApplication(configuration: Configuration): Promise; disableAccountStorageEvents(): void; enableAccountStorageEvents(): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1593,18 +1463,9 @@ export class PublicClientApplication implements IPublicClientApplication { getLogger(): Logger; getTokenCache(): ITokenCache; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - handleRedirectPromise( - hash?: string | undefined - ): Promise; + handleRedirectPromise(hash?: string | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - hydrateCache( - result: AuthenticationResult, - request: - | SilentRequest - | SsoSilentRequest - | RedirectRequest - | PopupRequest - ): Promise; + hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' initialize(request?: InitializeApplicationRequest): Promise; @@ -1614,9 +1475,7 @@ export class PublicClientApplication implements IPublicClientApplication { // (undocumented) protected isBroker: boolean; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - loginPopup( - request?: PopupRequest | undefined - ): Promise; + loginPopup(request?: PopupRequest | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen loginRedirect(request?: RedirectRequest | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1650,9 +1509,7 @@ export class PublicClientApplication implements IPublicClientApplication { // @public export class PublicClientNext implements IPublicClientApplication { // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - acquireTokenByCode( - request: AuthorizationCodeRequest - ): Promise; + acquireTokenByCode(request: AuthorizationCodeRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen acquireTokenPopup(request: PopupRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1660,14 +1517,9 @@ export class PublicClientNext implements IPublicClientApplication { // Warning: (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a parameter name // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" - acquireTokenSilent( - silentRequest: SilentRequest - ): Promise; + acquireTokenSilent(silentRequest: SilentRequest): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - addEventCallback( - callback: EventCallbackFunction, - eventTypes?: Array - ): string | null; + addEventCallback(callback: EventCallbackFunction, eventTypes?: Array): string | null; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag @@ -1680,9 +1532,7 @@ export class PublicClientNext implements IPublicClientApplication { // (undocumented) protected controller: IController; // (undocumented) - static createPublicClientApplication( - configuration: Configuration - ): Promise; + static createPublicClientApplication(configuration: Configuration): Promise; disableAccountStorageEvents(): void; enableAccountStorageEvents(): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1706,26 +1556,15 @@ export class PublicClientNext implements IPublicClientApplication { getLogger(): Logger; getTokenCache(): ITokenCache; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - handleRedirectPromise( - hash?: string | undefined - ): Promise; - // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - hydrateCache( - result: AuthenticationResult, - request: - | SilentRequest - | SsoSilentRequest - | RedirectRequest - | PopupRequest - ): Promise; + handleRedirectPromise(hash?: string | undefined): Promise; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + hydrateCache(result: AuthenticationResult, request: SilentRequest | SsoSilentRequest | RedirectRequest | PopupRequest): Promise; initialize(): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen initializeWrapperLibrary(sku: WrapperSKU, version: string): void; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - loginPopup( - request?: PopupRequest | undefined - ): Promise; + loginPopup(request?: PopupRequest | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen loginRedirect(request?: RedirectRequest | undefined): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen @@ -1766,26 +1605,12 @@ const redirectInIframe = "redirect_in_iframe"; // Warning: (ae-missing-release-tag) "redirectPreflightCheck" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -function redirectPreflightCheck( - initialized: boolean, - config: BrowserConfiguration -): void; +function redirectPreflightCheck(initialized: boolean, config: BrowserConfiguration): void; // Warning: (ae-missing-release-tag) "RedirectRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type RedirectRequest = Partial< - Omit< - CommonAuthorizationUrlRequest, - | "responseMode" - | "scopes" - | "earJwk" - | "codeChallenge" - | "codeChallengeMethod" - | "requestedClaimsHash" - | "platformBroker" - > -> & { +export type RedirectRequest = Partial> & { scopes: Array; redirectStartPage?: string; onRedirectNavigate?: (url: string) => boolean | void; @@ -1796,9 +1621,9 @@ export type RedirectRequest = Partial< // @public function replaceHash(url: string): void; -export { ServerError }; +export { ServerError } -export { ServerResponseType }; +export { ServerResponseType } // Warning: (ae-missing-release-tag) "SessionStorage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1827,21 +1652,14 @@ export class SessionStorage implements IWindowStorage { // // @public (undocumented) export class SignedHttpRequest { - constructor( - shrParameters: SignedHttpRequestParameters, - shrOptions?: SignedHttpRequestOptions - ); + constructor(shrParameters: SignedHttpRequestParameters, shrOptions?: SignedHttpRequestOptions); generatePublicKeyThumbprint(): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen removeKeys(publicKeyThumbprint: string): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen - signRequest( - payload: string, - publicKeyThumbprint: string, - claims?: object - ): Promise; + signRequest(payload: string, publicKeyThumbprint: string, claims?: object): Promise; } // Warning: (ae-missing-release-tag) "SignedHttpRequestOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1864,14 +1682,7 @@ const silentPromptValueError = "silent_prompt_value_error"; // Warning: (ae-missing-release-tag) "SilentRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type SilentRequest = Omit< - CommonSilentFlowRequest, - | "authority" - | "correlationId" - | "forceRefresh" - | "account" - | "requestedClaimsHash" -> & { +export type SilentRequest = Omit & { redirectUri?: string; extraQueryParameters?: StringDict; authority?: string; @@ -1891,17 +1702,7 @@ const spaCodeAndNativeAccountIdPresent = "spa_code_and_nativeAccountId_present"; // Warning: (ae-missing-release-tag) "SsoSilentRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type SsoSilentRequest = Partial< - Omit< - CommonAuthorizationUrlRequest, - | "responseMode" - | "earJwk" - | "codeChallenge" - | "codeChallengeMethod" - | "requestedClaimsHash" - | "platformBroker" - > ->; +export type SsoSilentRequest = Partial>; // Warning: (ae-missing-release-tag) "stateInteractionTypeMismatch" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1913,7 +1714,7 @@ const stateInteractionTypeMismatch = "state_interaction_type_mismatch"; // @public (undocumented) const storageNotSupported = "storage_not_supported"; -export { StringUtils }; +export { StringUtils } // Warning: (ae-missing-release-tag) "stubbedPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1923,18 +1724,16 @@ export const stubbedPublicClientApplication: IPublicClientApplication; // Warning: (ae-missing-release-tag) "stubbedPublicClientApplicationCalled" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const stubbedPublicClientApplicationCalled = - "stubbed_public_client_application_called"; +const stubbedPublicClientApplicationCalled = "stubbed_public_client_application_called"; -export { StubPerformanceClient }; +export { StubPerformanceClient } -export { TenantProfile }; +export { TenantProfile } // Warning: (ae-missing-release-tag) "unableToAcquireTokenFromNativePlatform" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const unableToAcquireTokenFromNativePlatform = - "unable_to_acquire_token_from_native_platform"; +const unableToAcquireTokenFromNativePlatform = "unable_to_acquire_token_from_native_platform"; // Warning: (ae-missing-release-tag) "unableToLoadToken" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1949,16 +1748,14 @@ const unableToParseState = "unable_to_parse_state"; // Warning: (ae-missing-release-tag) "unableToParseTokenRequestCacheError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const unableToParseTokenRequestCacheError = - "unable_to_parse_token_request_cache_error"; +const unableToParseTokenRequestCacheError = "unable_to_parse_token_request_cache_error"; // Warning: (ae-missing-release-tag) "uninitializedPublicClientApplication" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const uninitializedPublicClientApplication = - "uninitialized_public_client_application"; +const uninitializedPublicClientApplication = "uninitialized_public_client_application"; -export { UrlString }; +export { UrlString } // Warning: (ae-missing-release-tag) "userCancelled" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -2005,4 +1802,5 @@ export type WrapperSKU = (typeof WrapperSKU)[keyof typeof WrapperSKU]; // src/index.ts:8:4 - (tsdoc-undefined-tag) The TSDoc tag "@module" is not defined in this configuration // src/navigation/NavigationClient.ts:36:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // src/navigation/NavigationClient.ts:37:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + ``` From 05e23d6c7efa4d9df4ce0931dd0a4ca26ab6e84d Mon Sep 17 00:00:00 2001 From: Lalima Sharda Date: Wed, 14 May 2025 17:01:27 -0700 Subject: [PATCH 30/30] updating logger statements --- .../nativeBroker/PlatformAuthDOMHandler.ts | 16 +++++--- .../PlatformAuthExtensionHandler.ts | 38 ++++++++++--------- .../src/utils/BrowserConstants.ts | 4 +- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts index 05e2f19056..85aea2070d 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthDOMHandler.ts @@ -94,7 +94,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { request: PlatformBrokerRequest ): Promise { this.logger.trace( - "PlatformDOMHandler - Sending request to browser DOM API" + this.platformAuthType + " - Sending request to browser DOM API" ); try { @@ -108,7 +108,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { return this.validatePlatformBrokerResponse(response); } catch (e) { this.logger.error( - "PlatformDOMHandler: executeGetToken DOM API error" + this.platformAuthType + " - executeGetToken DOM API error" ); throw e; } @@ -118,7 +118,7 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { request: PlatformBrokerRequest ): PlatformDOMTokenRequest { this.logger.trace( - "NativeInteractionClient: initializeNativeDOMRequest called" + this.platformAuthType + " - initializeNativeDOMRequest called" ); const { @@ -169,7 +169,8 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { response.hasOwnProperty("expiresIn") ) { this.logger.trace( - "PlatformDOMHandler: platform broker returned successful and valid response" + this.platformAuthType + + " - platform broker returned successful and valid response" ); return this.convertToPlatformBrokerResponse( response as PlatformDOMTokenResponse @@ -182,7 +183,8 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { errorResponse.error.code ) { this.logger.trace( - "PlatformDOMHandler: platform broker returned error response" + this.platformAuthType + + " - platform broker returned error response" ); throw createNativeAuthError( errorResponse.error.code, @@ -206,7 +208,9 @@ export class PlatformAuthDOMHandler implements IPlatformAuthHandler { private convertToPlatformBrokerResponse( response: PlatformDOMTokenResponse ): PlatformBrokerResponse { - this.logger.trace("PlatformDOMHandler: convertToNativeResponse called"); + this.logger.trace( + this.platformAuthType + " - convertToNativeResponse called" + ); const nativeResponse: PlatformBrokerResponse = { access_token: response.accessToken, id_token: response.idToken, diff --git a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts index 9fcf899464..411b34512a 100644 --- a/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts +++ b/lib/msal-browser/src/broker/nativeBroker/PlatformAuthExtensionHandler.ts @@ -79,7 +79,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { async sendMessage( request: PlatformBrokerRequest ): Promise { - this.logger.trace("PlatformAuthExtensionHandler - sendMessage called."); + this.logger.trace(this.platformAuthType + " - sendMessage called."); // fall back to native calls const messageBody: NativeExtensionRequestBody = { @@ -95,12 +95,13 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { }; this.logger.trace( - "PlatformAuthExtensionHandler - Sending request to browser extension" + this.platformAuthType + " - Sending request to browser extension" ); this.logger.tracePii( - `PlatformAuthExtensionHandler - Sending request to browser extension: ${JSON.stringify( - req - )}` + this.platformAuthType + + ` - Sending request to browser extension: ${JSON.stringify( + req + )}` ); this.messageChannel.port1.postMessage(req); @@ -154,7 +155,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { */ private async sendHandshakeRequest(): Promise { this.logger.trace( - "PlatformAuthExtensionHandler - sendHandshakeRequest called." + this.platformAuthType + " - sendHandshakeRequest called." ); // Register this event listener before sending handshake window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first @@ -211,9 +212,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { * @param event */ private onWindowMessage(event: MessageEvent): void { - this.logger.trace( - "PlatformAuthExtensionHandler - onWindowMessage called" - ); + this.logger.trace(this.platformAuthType + " - onWindowMessage called"); // We only accept messages from ourselves if (event.source !== window) { return; @@ -242,7 +241,8 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { */ if (!handshakeResolver) { this.logger.trace( - `PlatformAuthExtensionHandler.onWindowMessage - resolver can't be found for request ${request.responseId}` + this.platformAuthType + + `.onWindowMessage - resolver can't be found for request ${request.responseId}` ); return; } @@ -275,7 +275,7 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { */ private onChannelMessage(event: MessageEvent): void { this.logger.trace( - "PlatformAuthExtensionHandler - onChannelMessage called." + this.platformAuthType + " - onChannelMessage called." ); const request = event.data; @@ -293,12 +293,14 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { } const response = request.body.response; this.logger.trace( - "PlatformAuthExtensionHandler - Received response from browser extension" + this.platformAuthType + + " - Received response from browser extension" ); this.logger.tracePii( - `PlatformAuthExtensionHandler - Received response from browser extension: ${JSON.stringify( - response - )}` + this.platformAuthType + + ` - Received response from browser extension: ${JSON.stringify( + response + )}` ); if (response.status !== "Success") { resolver.reject( @@ -333,7 +335,8 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { } else if (method === NativeExtensionMethod.HandshakeResponse) { if (!handshakeResolver) { this.logger.trace( - `PlatformAuthExtensionHandler.onChannelMessage - resolver can't be found for request ${request.responseId}` + this.platformAuthType + + `.onChannelMessage - resolver can't be found for request ${request.responseId}` ); return; } @@ -346,7 +349,8 @@ export class PlatformAuthExtensionHandler implements IPlatformAuthHandler { this.extensionId = request.extensionId; this.extensionVersion = request.body.version; this.logger.verbose( - `PlatformAuthExtensionHandler - Received HandshakeResponse from extension: ${this.extensionId}` + this.platformAuthType + + ` - Received HandshakeResponse from extension: ${this.extensionId}` ); this.handshakeEvent.end({ extensionInstalled: true, diff --git a/lib/msal-browser/src/utils/BrowserConstants.ts b/lib/msal-browser/src/utils/BrowserConstants.ts index c5c6b72d45..750c5318fc 100644 --- a/lib/msal-browser/src/utils/BrowserConstants.ts +++ b/lib/msal-browser/src/utils/BrowserConstants.ts @@ -48,8 +48,8 @@ export const PlatformAuthConstants = { MICROSOFT_ENTRA_BROKERID: "MicrosoftEntra", DOM_API_NAME: "DOM API", PLATFORM_DOM_APIS: "get-token-and-sign-out", - PLATFORM_DOM_PROVIDER: "PlatformDOMHandler", - PLATFORM_EXTENSION_PROVIDER: "NativeMessageHandler", + PLATFORM_DOM_PROVIDER: "PlatformAuthDOMHandler", + PLATFORM_EXTENSION_PROVIDER: "PlatformAuthExtensionHandler", }; export const NativeExtensionMethod = {