import type { IAadTokenProviderConfiguration } from '../../IAadTokenProvider'; import type { IGetTokenDataOptions, IGetTokenOptions, ITokenData } from '../../ITokenProvider'; /** * Class that wraps the MSAL Browser's authentication class in order to acquire tokens. * * MsalBrowserTokenProvider provides two methods to acquire tokens: * 1. getToken: returns a promise containing only the access token string. * 2. getTokenData: returns a promise containing the entire token object. * * @internal */ export declare class MsalBrowserTokenProvider { private readonly _defaultConfiguration; private _msalBrowserClient; private _redirectCancelled; private _redirectManager; private _shouldPrintDebugLogs; private _ensureStateResult; private _pendingPopupAuth; private readonly _ALLOWED_NETWORK_RETRY_ATTEMPTS; constructor(configuration: IAadTokenProviderConfiguration); /** * This method wraps getTokenData() to extract only the access token from the response. * The access token is returned as a promise containing a string. If the entire token object * from MSAL is needed the caller should use getTokenData(). * * The caller only needs to provide the resource they are requesting and the token provider * will use always use the scope '.default'. E.g.: "resourceEndpoint/.default". * * **Events raised**: * - {@link PopupEventArgs} (AadTokenProvider._popupEventId): Raised when silent token acquisition fails * and user interaction via popup is required. Subscribe to this event to show custom UI, * prevent popups, or control popup timing. **NAA Exception**: NOT raised when NAA is active. * - {@link BeforeRedirectEventArgs} (AadTokenProvider._onBeforeRedirectEventId): Raised before full-page * redirect for authentication. Subscribe to cancel redirect, save application state, or * implement custom redirect handling. **NAA Exception**: NOT raised when NAA is active. * * @param resourceEndpoint - The endpoint the caller is requesting a resource from. * @returns A promise with only the access token (as a string) for the resource. */ getToken(resourceEndpoint: string, options?: IGetTokenOptions): Promise; getToken(resourceEndpoint: string, useCachedToken?: boolean): Promise; /** * Gets an access token for the requested resource from MSAL. This method returns the entire token * object as a promise. * * **Authentication Flow**: * This method will attempt authentication in the following order: * 1. Silent token acquisition via `acquireTokenSilent()` or `ssoSilent()` * 2. Popup authentication (if silent fails and interaction required) * 3. Full-page redirect (if popup unavailable or fails) * * **PoP Token Handling**: * - When `authenticationScheme: IAuthenticationScheme.POP`, fetches nonce via `_getShrNonce()` * - If nonce fetch fails with `NonceNotSupported`, falls back to BEARER tokens * - Caches PoP-not-supported resources for 5 days to avoid repeated nonce attempts * * **CAP Error Retry**: * - When CAP errors occur during ensure request (AADSTS16000, 53000-53003), retries with empty resource and undefined scopes * - Only retries once per request to avoid infinite loops * * **Request Queueing**: * AcquireControl() places this request in a queue that will either: * - wait for the previous request to finish * - continue after 10s * * **Delegation**: Delegates actual token acquisition to `_getTokenDataInternal()` after PoP nonce handling. * * **Events raised**: * - {@link PopupEventArgs} (AadTokenProvider._popupEventId): Raised when silent token acquisition fails * and user interaction via popup is required. Subscribe to this event to show custom UI, * prevent popups, or control popup timing. **NAA Exception**: NOT raised when NAA is active. * - {@link BeforeRedirectEventArgs} (AadTokenProvider._onBeforeRedirectEventId): Raised before full-page * redirect for authentication. Subscribe to cancel redirect, save application state, or * implement custom redirect handling. **NAA Exception**: NOT raised when NAA is active. * * @param resourceEndpoint - The resource a token is being requested for. * @param useCachedToken - Whether or not the token provider should use a cached token or fetch a new one. * Note: this parameter currently does not do anything. It exists in MSAL v1 and also * does not do anything there. I've included it here to maintain the same * function signature. * @param shouldNotLogOrRedirect - If true, logging will be disabled and redirects will not occur. * @returns A promise containing entire token object from msal-browser. */ getTokenData(resourceEndpoint: string, options?: IGetTokenDataOptions): Promise; getTokenData(resourceEndpoint: string, useCachedToken?: boolean, skipLoggingAndDisableRedirects?: boolean): Promise; /** * Ensures authentication state is initialized before attempting token acquisition. * * **Purpose**: * Establishes the initial authentication state by checking for redirect responses, * processing EAR (Encrypted Authorization Response) cookies, and attempting silent * token acquisition to populate MSAL's cache. This ensures subsequent token requests * can succeed silently without requiring user interaction. * * **Caching**: * - Called once per provider instance (result cached in `_ensureStateResult`) * - Subsequent calls return the same promise to avoid redundant state initialization * - NOT called when `isEnsureRequest: true` to prevent deadlock (avoid calling ensure during ensure) * * **Flow**: * 1. **EAR Cookie Processing** - If available, processes encrypted auth response from server-side redirect * 2. **Silent Token Request** - Attempts `getTokenData()` for Graph endpoint with only: * - `isEnsureRequest: true` to skip recursive _ensureState() calls * - Note: Does NOT set `cancelRedirect` or `skipLoggingAndDisableRedirects` * 3. **Broker Initialization** - If pairwise brokering enabled, initializes broker after state established * * **Graph Endpoint Fallback**: * Uses Graph API (https://graph.microsoft.com/.default) as the default resource for initial token * acquisition because it's universally available across tenants and scenarios. This populates the * MSAL cache with account and refresh token information that can be used for subsequent requests. * * **Broker Initialization**: * - Initializes pairwise brokering after successful state establishment * - On failure during ensure, retries broker initialization before propagating error * - Only runs when `isPairwiseBrokerEnabled` and NAA not supported * * **Failure Classification**: * - Expected failures: User cancelled, popup blocked, interaction required, known AAD errors * - Unexpected failures: Network errors, MSAL errors, unknown exceptions * - Popup/cancel errors during ensure are treated as expected (user may block popup legitimately) * * @returns Promise that resolves when authentication state is initialized, or rejects with error */ _ensureState(): Promise; _ensureTelemetry(): Promise; /** * Initializes pairwise broker for cross-origin token sharing between web applications. * * **Purpose**: * Sets up the pairwise broker component that allows MSAL to share tokens across different * origins and domains. This enables SSO (Single Sign-On) across web applications without * requiring repeated authentication. * * **When Called**: * - After `_ensureState()` completes successfully (in success path) * - After `_ensureState()` throws error (in catch block) * - Only when BOTH conditions are met: * 1. NAA not supported * 2. Pairwise broker enabled in configuration (`isPairwiseBrokerEnabled: true`) * * **Initialization Flow**: * 1. Creates `InitializeBrokering` QoS monitor * 2. Generates new correlation ID for broker telemetry * 3. Gets MSAL client instance via `MsalBrowserClientManager.getMsalBrowserClient()` * 4. Casts client to `PairwiseBrokerApplication` * 5. Calls `initializeBrokering()` with optional correlation ID * 6. Logs success or unexpected failure to QoS * * **Error Handling**: * Failures are logged as unexpected and will cause `_ensureState()` to fail. If broker * initialization fails during the success path, the entire state establishment operation * will be rejected. In the error recovery path, broker initialization is attempted but * the original error is always propagated regardless of broker init success or failure. * * @returns Promise that resolves when broker initialized, or rejects with error */ private _initializeBrokering; /** * Core implementation of authentication state initialization logic. * * **Purpose**: * Performs the actual work of establishing authentication state by processing server-side * redirect tokens or acquiring an initial token silently. Called by `_ensureState()` which * handles caching and broker initialization. * * **EAR Cookie Processing Flow**: * 1. **Check for EAR cookie** - Looks for `spa_rt` (encrypted authorization response) cookie chunks * 2. **Validate expiration** - Compares cookie expiration with locally stored expiration date * 3. **Load into MSAL cache** - Uses `loadExternalTokens()` to populate cache with refresh token and account info * 4. **Set active account** - Marks the account as active for subsequent silent token requests * 5. **Store expiration** - Saves expiration date to avoid reprocessing same cookie * * **When EAR Cookie is Used**: * - Cookie is present (`spa_rt` has value) * - No local expiration stored, OR stored expiration differs from cookie expiration * - Ensures fresh tokens from server-side redirects are prioritized over stale cached state * * **When EAR Cookie is Skipped**: * - Cookie already processed (expiration matches local storage and is still valid) * - No cookie present (user hasn't redirected recently) * - Claims challenge in progress (don't want to override with non-claims token) * * **Graph Endpoint Fallback**: * If no EAR cookie is available or processed, attempts silent token acquisition for MS Graph * endpoint to populate MSAL cache. Graph is used as a universal resource available across * all tenants and scenarios. This request only sets: * - `isEnsureRequest: true` to prevent recursive `_ensureState()` calls * * @returns Promise that resolves when state is initialized, or rejects with error */ private _ensureStateHelper; private _getEncryptedAuthorizedResponseToken; private _getCookieData; private _setRefreshTokenExpirationDate; private _hasUserRedirectedInLastFiveDays; private _getUsersLastRedirectTimeFromLocalStorage; private _setUsersLastRedirectTimeInLocalStorage; private _clearUsersLastRedirectTimeInLocalStorage; private _getProcessedTokenExpirationDate; private _isProcessedTokenExpirationDateValid; private _getShrNonce; /** * Core token acquisition method that implements the full authentication flow. * * **Authentication Flow**: * 1. **Silent Authentication** - Tries `acquireTokenSilent()` (if logged in) or `ssoSilent()` (if not logged in) * 2. **Popup Authentication** - If silent fails with interaction required and popup not pending * 3. **Redirect Authentication** - If popup unavailable, fails, or is cancelled * * **Popup Debouncing**: * - Waits for pending popup before attempting another * - Only one popup can be active at a time to prevent browser blocking * * **CAP Error Retry**: * - On CAP errors (AADSTS16000, 53000-53003) during ensure request, retries with empty resource and undefined scopes * - Only retries once (when `isRetry === false`) to prevent infinite loops * * **Expected vs Unexpected Failures**: * - Expected: User cancelled, access denied, interaction required, known AAD errors * - Unexpected: Network failures, MSAL errors, timeout errors * * **Events raised**: * - `tokenAcquisitionEvent` (popup event): Raised in `handlePopupAuth()` when interaction required * - `onBeforeRedirectEvent` (redirect event): Raised in `handleRedirectAuth()` before redirect * * @param requestContext - Contains request parameters (resource, scopes, login hint, telemetry) * @param options - Token acquisition options (useCachedToken, skipLoggingAndDisableRedirects, etc.) * @param isRetry - Whether this is a retry attempt (prevents infinite retry loops) * @returns Promise with token data containing accessToken, expiresOn, etc. */ private _getTokenDataInternal; /** * Returns a promise that only resolves once the Msal Browser client has been initialized and assigned. * If the client hasn't been initialized, MsalBrowserClientManager will provide an initialized one. * * @param requestContext - The request context for this request. * @returns The promise fulfils when this._msalBrowserClient has been initialized for use. */ private _ensureMsalClientIsInitialized; /** * Wrapper method for msalBrowser.acquireTokenSilent(). This method is used when the current user is already * logged into the msal-browser framework. It will retry if there are any detectable network issues * during msalBrowser.acquireTokenSilent(). * * **When used**: * Called from `_getTokenDataInternal()` when `_isCurrentUserLoggedInToMsal()` returns true, meaning: * - An active account is set in MSAL * - User has previously authenticated and MSAL has cached account information * - This is a subsequent token request (not the first authentication) * * **Token Acquisition Flow**: * 1. **Cache lookup** - MSAL first checks for valid unexpired access token in cache * 2. **Refresh token** - If no valid access token, uses refresh token to get new access token from AAD * 3. **Network call** - Refresh token exchange happens silently without user interaction * * **Network Retry Logic**: * - Retries on retriable network errors (timeouts, connection failures) * - Maximum retry attempts: `_ALLOWED_NETWORK_RETRY_ATTEMPTS` (default: 1) * - Only retries errors classified as `_isRetriableNetworkError()` * - Each retry attempt is tracked separately with `RetryAcquireTokenSilent` monitor * * **Failure Classification**: * - Expected failures: User cancelled, consent required, interaction required, access denied * - Unexpected failures: Network errors, MSAL errors, invalid tokens, AAD service errors * * **Request Generation**: * Uses `_generateSilentRequest()` to build request with: * - Scopes from resource endpoint * - Authority (tenant URL) * - Account (current logged-in account) * - Claims (if claims challenge present) * - PoP parameters (if PoP tokens requested) * * **Difference from _ssoSilent()**: * - `_acquireTokenSilent()`: User logged in, has account, uses refresh token * - `_ssoSilent()`: No user logged in, attempts SSO with session ID/UPN, may create new account * * The retry monitor is only invoked on retries and is considered failed each time an error has raised. The * acquireTokenSilentMonitor will be re-used on each retry. * * @param requestContext - The request context for this request. * @param acquireTokenSilentMonitor - The monitor tracking the request. * @param attempt - The current attempt number. This method may invoke itself in an attempt to retry. * @returns A promise containing the access token and full authentication response object from msal-browser. */ private _acquireTokenSilent; /** * Wrapper method for msalBrowser.ssoSilent(). This method is used when the current user is not logged * into the msal-browser framework. It will retry if there are any detectable network issues during * msalBrowser.ssoSilent(). * * **When used**: * Called from `_getTokenDataInternal()` when `_isCurrentUserLoggedInToMsal()` returns false, meaning: * - No active account set in MSAL * - User hasn't authenticated yet in this session * - This is likely the first token request or after cache cleared * * **SSO Silent Flow**: * 1. **Session cookie lookup** - MSAL checks for AAD session cookies in browser * 2. **Silent iframe** - Opens hidden iframe to AAD `/authorize` endpoint * 3. **SSO authentication** - If user has valid AAD session, AAD returns tokens silently * 4. **Account creation** - MSAL creates account object and caches tokens * 5. **Set active account** - New account becomes active for subsequent requests * * **Login Hint Strategy (fallback order)**: * 1. **SESSION_ID** - Preferred, uses AAD session ID for guaranteed user match * 2. **UPN** - Fallback, uses user principal name (email) if session ID unavailable * 3. **NONE** - Last resort, no hint provided (may prompt user to select account) * * The login hint ensures the correct user is authenticated when multiple accounts exist. * Generated by `_generateSsoSilentRequest()` based on available user information. * * **Network Retry Logic**: * - Retries on retriable network errors (timeouts, connection failures) * - Maximum retry attempts: `_ALLOWED_NETWORK_RETRY_ATTEMPTS` (default: 1) * - Only retries errors classified as `_isRetriableNetworkError()` * - Each retry attempt is tracked separately with `RetrySsoSilent` monitor * * **Failure Classification**: * - Expected failures: No session exists, consent required, interaction required * - Unexpected failures: Network errors, MSAL errors, AAD service errors * * **Difference from _acquireTokenSilent()**: * - `_ssoSilent()`: No user logged in, attempts SSO with session ID/UPN, may create new account * - `_acquireTokenSilent()`: User logged in, has account, uses refresh token * * The retry monitor is only invoked on later attempts and is considered failed each time an error has * raised. The ssoSilentMonitor will be re-used on each retry. * * @param requestContext - The request context for this request. * @param ssoSilentMonitor - The monitor tracking the request. * @param attempt - The current attempt number. This method may invoke itself in an attempt to retry. * @returns A promise containing the access token and full authentication response object from msal-browser. */ private _ssoSilent; /** * Performs a full-page redirect to AAD for interactive authentication. * * **Purpose**: * Navigates the browser to AAD login page when silent and popup authentication both fail or * are unavailable. This is the fallback authentication method that always works but causes * full page navigation and loss of application state. * * **When used**: * - Silent authentication fails with interaction required, AND: * - EITHER: Both popup authentication is disabled AND NAA is not supported (top-level browser context) * - Popup can be disabled by tenant configuration (`Set-SPOTenant -IsEnableAppAuthPopupEnabled $false`) in sp-client areas * - Popup can be disabled by caller/app context based on codepath requirements in odsp-next areas * - NAA is not supported when not running in Teams, Outlook, or supported mobile webviews * - OR: Popup authentication was attempted but failed (top-level browser context): * - User closed popup window before completing authentication * - Browser popup blocker prevented the popup from opening * - MSAL acquireTokenPopup() threw an error * * **Note**: NAA failure does NOT lead to redirect because NAA environments (Teams, Outlook, mobile webviews) * run in iframes where redirect is blocked. When NAA fails, the error is thrown to the caller. * * **Redirect Flow**: * 1. **Prepare redirect state** - Calls `_redirectManager.prepareForRedirect()` to save: * - Correlation ID for tracking the redirect round-trip * - Current URL for post-auth navigation back * - Request context for resuming after redirect * 2. **Save invalid session IDs** - Stores session IDs that failed to avoid reusing them * 3. **Raise BeforeRedirectEvent** - Fires event allowing consumers to cancel or prepare for redirect * 4. **Navigate to AAD** - Calls `loginRedirect()` which immediately navigates to AAD login page * 5. **Post-auth redirect** - AAD redirects back to `spfxsinglesignon.aspx` with auth code * 6. **Handle redirect response** - MSAL processes response on redirect page, exchanges code for tokens * * **Redirect Page**: * Uses `spfxsinglesignon.aspx` as the redirect URI. This page: * - Reads redirect state from `_redirectManager` * - Initializes MSAL with correct configuration * - Calls `handleRedirectPromise()` to process AAD response * - Navigates back to original URL after token acquisition * * **Deduplication**: * Redirect manager tracks recent redirects (5-day window) to prevent redirect loops: * - Checks if same resource redirected recently * - Blocks repeated redirects to same endpoint * - Prevents infinite redirect cycles * * **Error Handling**: * If MSAL aborts the redirect (e.g., detected iframe context), calls `_redirectManager.cancelRedirect()` * to clean up redirect state. This prevents future requests from thinking a redirect is pending. * * **Request Generation**: * Uses `_generateLoginRedirectRequest()` to build request with: * - Scopes from resource endpoint * - Authority (tenant URL) * - Login hint (session ID or UPN) * - Redirect URI (spfxsinglesignon.aspx) * - PoP parameters (if PoP tokens requested) * * **Events raised**: * - `onBeforeRedirectEvent`: Raised before navigation, allows cancellation or state saving * * @param requestContext - The request context for this request. * @returns Promise that rejects if redirect fails, otherwise never returns (page navigates away). */ private _loginRedirect; /** * Handles NAA (Nested App Auth) popup authentication for brokered authentication flows. * * **Purpose**: * Specialized popup authentication for NAA-enabled environments (Teams, Outlook, mobile apps). * NAA uses the host application as an authentication broker, providing seamless SSO without * traditional popup windows or full-page redirects. * * **When used**: * Called from `_getTokenDataInternal()` when: * - `_defaultConfiguration.isNaaSupported` is true (broker detected) * - Silent authentication fails with interaction required error * - NAA broker available (Teams app, Outlook, mobile webview) * * **NAA Broker Flow**: * 1. **Broker detection** - MSAL detects host app capability (Teams, Outlook, etc.) * 2. **Account picker** - Broker shows native account picker UI (not browser popup) * 3. **Silent authentication** - Broker handles auth without exposing credentials to web app * 4. **Token return** - Broker returns tokens to web app via secure channel * * **Difference from _acquireTokenPopup()**: * - `_acquireTokenPopup()`: Browser popup, popup debouncing, event system, manual control * - `_acquireTokenPopupNAA()`: Native broker, no popup window, no debouncing, no events * * **Benefits**: * - No popup blocker issues (uses native UI) * - Better mobile experience (native auth flow) * - Seamless SSO with host application * - Faster authentication (no page load) * * **Active Account**: * On successful authentication, sets the returned account as active in MSAL for subsequent * silent requests. This ensures the correct account is used when multiple accounts exist. * * **Failure Classification**: * - Expected failures: User cancelled, access denied, consent required * - Unexpected failures: Broker errors, network errors, MSAL errors * * @param requestContext - The request context for this request. * @returns Promise resolving with token data from NAA broker. */ private _acquireTokenPopupNAA; /** * Handles popup-based authentication when silent token acquisition fails with interaction required. * * **Purpose**: * Opens a popup window to AAD login page for interactive authentication. Used when: * - Silent authentication fails (no cached token, no refresh token) * - User consent is required * - Multi-factor authentication needed * - Conditional Access Policy requires user interaction * * **Popup Debouncing**: * Only one popup can be active at a time to prevent browser popup blocking: * - Uses a single `_pendingPopupAuth` promise to track ongoing popup authentication * - Waits for `_pendingPopupAuth` to complete before opening a new popup * - Returns a promise that resolves with token data once the popup completes * * **Event Flow**: * 1. **Raise PopupEvent** - Fires `AadTokenProvider._popupEventId` event with PopupEventArgs * 2. **Consumer can cancel** - Event handlers can call `cancel()` to prevent popup * 3. **Consumer can delay** - Event handlers can call `requestPopup()` then manually call `showPopup()` later * 4. **Auto-show popup** - If not cancelled or manually controlled, popup opens automatically * * **PopupEventArgs callbacks**: * - `cancel(error?)` - Cancels popup, rejects promise, writes expected failure to QoS * - `requestPopup()` - No-op placeholder for consumer to request popup control * - `showPopup()` - Opens popup window, calls MSAL `acquireTokenPopup()` * * **Active Account**: * On successful authentication, sets the returned account as active in MSAL for subsequent * silent requests. This ensures the correct account is used when multiple accounts exist. * * **Failure Classification**: * - Expected failures: User cancelled, popup blocked, access denied, user closed popup * - Unexpected failures: Network errors, MSAL errors, popup errors * * **Request Generation**: * Uses `_generatePopupRequest()` to build request with: * - Scopes from resource endpoint * - Authority (tenant URL) * - Login hint (session ID or UPN) * - Prompt type (select_account, consent, etc.) * - PoP parameters (if PoP tokens requested) * * @param requestContext - The request context for this request. * @param popupMonitor - The monitor tracking the popup request. * @returns Promise resolving with token data once the popup completes. */ private _acquireTokenPopup; /** * Generates an MSAL SilentRequest to be used with acquireTokenSilent method. * * **Purpose**: * Builds request configuration for silent token acquisition when user is already logged into MSAL. * This request attempts to get tokens from cache or using refresh token without user interaction. * * **Request Components**: * - **account**: Current logged-in account from `_getCurrentAccount()` (required for acquireTokenSilent) * - **authority**: Tenant-specific AAD endpoint * - **scopes**: OAuth scopes for resource (from `_getScopes()` or requestContext) * - **correlationId**: Tracking ID for telemetry and debugging * - **claims**: Optional claims challenge from CAP policy * - **cacheLookupPolicy**: Controls cache vs network behavior * * **Cache Lookup Policy**: * - **Default (useCachedToken=true)**: MSAL uses default policy (cache first, then refresh token) * - **Skip cache (useCachedToken=false)**: Forces `RefreshTokenAndNetwork` policy to bypass cache * and always fetch fresh token from network using refresh token * * **When cache is skipped** (`useCachedToken=false`): * - Ensures fresh token for sensitive operations * - Bypasses potentially stale cached tokens * - Still uses refresh token (no user interaction) * - Useful after claims challenge or CAP policy changes * * **PoP Token Support**: * When `authenticationScheme === IAuthenticationScheme.POP`: * - Sets `resourceRequestUri` to target endpoint * - Sets `authenticationScheme` to PoP * - Includes `resourceRequestMethod` (GET, POST, etc.) * - Includes `shrNonce` (nonce from resource server) * - Includes `shrClaims` (additional PoP claims) * * **Used by**: `_acquireTokenSilent()` when user logged into MSAL * * @param requestContext - The request context for this request. * @returns An MSAL SilentRequest object. */ private _generateSilentRequest; /** * Applies login hint strategy to MSAL request objects by setting either session ID or UPN. * * **Purpose**: * Implements the login hint fallback strategy (SESSION_ID → UPN → NONE) for SSO silent * and popup authentication requests. Login hints improve authentication success rates by * providing AAD with user identification without requiring interactive sign-in. * * **Login Hint Strategy Priority**: * 1. **SESSION_ID** (preferred): Uses `sid` parameter with AAD session ID * - Requires valid GUID format (via `Guid.tryParse()`) * - Skipped if session ID is in invalid list (`MsalSessionIdManager.isSessionIdInvalid()`) * - Falls back to UPN if session ID unavailable or invalid * 2. **UPN** (fallback): Uses `loginHint` parameter with userPrincipalName * - Used when session ID unavailable, invalid, or previously failed * - Falls back to NONE if UPN unavailable * 3. **NONE** (last resort): Both `sid` and `loginHint` set to undefined * - No user identification provided * - May require interactive authentication or full-page redirect * * **Side Effects**: * - Modifies `requestData.sid` and `requestData.loginHint` parameters * - Updates `requestContext.loginHintType` to track current strategy being used * - Strategy changes are logged in telemetry for debugging SSO failures * * **Used By**: * - `_generateSsoSilentRequest()` - SSO silent authentication * - `_generatePopupRequest()` - Popup authentication * - Conditionally by `_generateLoginRedirectRequest()` based on feature flag * * **Session ID Validation**: * Session ID must pass two validation checks: * 1. Must be valid GUID format (checked by `_getSessionId()`) * 2. Must not be in invalid list (checked by `MsalSessionIdManager.isSessionIdInvalid()`) * * @param requestData - MSAL request object (SsoSilentRequest or PopupRequest) to modify * @param requestContext - Contains current login hint type and telemetry data */ private _setLoginHint; /** * Generates an MSAL SsoSilentRequest to be used with the ssoSilent method. * * **Purpose**: * Builds request configuration for SSO silent authentication when no user is logged into MSAL. * This request attempts to establish authentication using existing AAD session cookies. * * **Request Components**: * - **authority**: Tenant-specific AAD endpoint (e.g., https://login.microsoftonline.com/tenant-id) * - **scopes**: OAuth scopes for resource (from `_getScopes()` or requestContext) * - **correlationId**: Tracking ID for telemetry and debugging * - **claims**: Optional claims challenge from CAP policy * - **Login hint**: Session ID (sid) or UPN (loginHint) for user identification * * **Login Hint Strategy**: * Calls `_setLoginHint()` which attempts in fallback order: * 1. **SESSION_ID**: AAD session ID from `_getSessionId()` - most reliable * 2. **UPN**: User principal name (email) - fallback when session ID unavailable * 3. **NONE**: No hint provided - may prompt user or fail * * Note: SID and login hint may be undefined if non-existent or invalid session. This * may cause the request to fail with interaction required, falling back to popup or redirect. * * **PoP Token Support**: * When `authenticationScheme === IAuthenticationScheme.POP`: * - Sets `resourceRequestUri` to target endpoint * - Sets `authenticationScheme` to PoP * - Includes `resourceRequestMethod` (GET, POST, etc.) * - Includes `shrNonce` (nonce from resource server) * - Includes `shrClaims` (additional PoP claims) * * **Used by**: `_ssoSilent()` when user not logged into MSAL * * @param requestContext - The request context for this request. * @returns An MSAL SsoSilentRequest object. */ private _generateSsoSilentRequest; /** * Generates an MSAL PopupRequest to be used with acquireTokenPopup method. * * **Purpose**: * Builds request configuration for popup-based interactive authentication when silent * authentication fails and user interaction is required. * * **Request Components**: * - **account**: Current logged-in account from `_getCurrentAccount()` (may be null) * - **authority**: Tenant-specific AAD endpoint * - **scopes**: OAuth scopes for resource (from `_getScopes()` or requestContext) * - **correlationId**: Tracking ID for telemetry and debugging * - **claims**: Optional claims challenge from CAP policy * - **Login hint**: Session ID (sid) or UPN (loginHint) for user identification * * **Account vs Login Hint**: * - If account exists (user logged in), MSAL uses account for authentication * - If no account, uses login hint (session ID or UPN) to identify user * - Login hint ensures correct account selected when multiple AAD sessions exist * * **PoP Token Support**: * When `authenticationScheme === IAuthenticationScheme.POP`: * - Sets `resourceRequestUri` to target endpoint * - Sets `authenticationScheme` to PoP * - Includes `resourceRequestMethod` (GET, POST, etc.) * - Includes `shrNonce` (nonce from resource server) * - Includes `shrClaims` (additional PoP claims) * * **Used by**: * - `_acquireTokenPopup()`: Standard popup authentication * - `_acquireTokenPopupNAA()`: NAA broker authentication * * @param requestContext - The request context for this request. * @returns An MSAL PopupRequest object. */ private _generatePopupRequest; /** * Generates telemetry data to be added to QoS Monitors. We track: * - alias: Marks cache hits. This will be true if the request came from the cache. * - aadSessionId: AAD Session ID used in ssoSilent scenarios. * - CorrelationId: The correlation ID of the token request. * - isInternal: True if first party application ID. * - isPageVisibleStart: True if page is visible at scenario start. * - isPageVisibleEnd: True if page is visible at scenario end. * - redirectUri: redirect URI used in redirect and ssoSilent scenarios * * @param resourceEndpoint - The resource a token is being requested for. * @returns An IMsalBrowserTokenProviderExtraData object that can be added to QoS Monitor writes. */ private _generateTelemetryData; /** * Given an error, this method will return true if the token provider is allowed to redirect * and the error can be solved with a redirect. * * Note: Redirects are not performed for IE. * * @param error - An msalBrowser AuthError. * @returns True if the error can be solved with a redirect and there are remaining redirects. */ private _isErrorEligibleForRedirect; /** * Determines whether popup authentication should be attempted for interactive flows. * * **Purpose**: * Checks configuration flag to decide if popup window authentication is enabled. When false, * authentication falls back to full-page redirect immediately without attempting popup. * * **Configuration Source**: * Reads `isMsalTokenProviderPopupEnabled` from `_defaultConfiguration`. This value can come from: * * **Default (Standard Flow)**: * - Server sends tenant setting from `Set-SPOTenant -IsEnableAppAuthPopupEnabled` (default: false) * - Property flow: Server → `IsMsalTokenProviderPopupEnabled` (page context) → `isMsalTokenProviderPopupEnabled` (config) * * **Application Overrides (Custom Configurations)**: * - Applications can create custom configs or use `tokenProviderConfigurationOverrides` * - May set based on: killswitches, browser capabilities (isWebClient), application context, etc. * - Examples: MetaOS (killswitch + isWebClient), WAC (usePopup variable), Copilot scenarios (false) * * **This method only reads the value** - it does not determine it based on runtime conditions * * **Used by**: * - `_getTokenDataInternal()`: Decides whether to attempt popup after silent auth fails * - Controls authentication flow: Silent → Popup (if enabled) → Redirect * * **Note**: Even when enabled, popup may still fail due to browser blocking, at which point * the flow falls back to redirect anyway. * * @returns True if popup authentication is enabled, false to skip directly to redirect. */ private _shouldUsePopup; /** * Given an error, this method will return true if the provided error is any type of 'Interaction Required' * error. These errors can be solved by invoking a full-page redirect (interaction). * * @param error - An msal-browser AuthError. * @returns True if the error provided can be solved by a redirect and false otherwise. */ private _isInteractionRequiredError; /** * Given an msal-browser AuthError, returns true if the error is an expected failure for QoS Monitors. * These errors can either be ignored (i.e., TabStop test) or solved by a full-page redirect (as long as * there are redirect attempts remaining). * * @param error - An msal-browser AuthError. * @returns True if the error is expected and be recorded as successful for QoS Monitors. */ private _isExpectedFailure; private _isMonitorTimeoutFailure; /** * This method returns true if a TabStop test is currently being run. TabStop tests are * known to cause issues and so they are generally recorded as expected failures. * * @returns True if a TabStop test is running. */ private _isTabStopTest; /** * Generates an MSAL RedirectRequest to be used with the loginRedirect method. * * **Purpose**: * Builds request configuration for full-page redirect authentication when silent and popup * authentication both fail or are unavailable. This is the fallback authentication method. * * **Request Components**: * - **authority**: Tenant-specific AAD endpoint * - **scopes**: OAuth scopes for resource (from `_getScopes()`) * - **correlationId**: Tracking ID for telemetry and debugging * - **redirectUri**: URL where AAD redirects after auth (spfxsinglesignon.aspx) * - **state**: Current page URL for post-auth navigation back * - **claims**: Optional claims challenge from CAP policy * - **onRedirectNavigate**: Callback to cancel redirect or raise events before navigation * - **Login hint**: Session ID (sid) or UPN (loginHint) for user identification * * **State Management**: * The `state` field contains `window.location.href` so MSAL can navigate back to the * original page after authentication completes. This preserves the user's location * before the redirect interrupted their flow. * * **onRedirectNavigate Callback**: * Generated by `_getOnRedirectNavigate()`, this callback: * - Raises `BeforeRedirectEvent` allowing consumers to cancel or prepare for redirect * - Returns false to cancel redirect if event handler calls `cancel()` * - Returns true to proceed with redirect navigation * * **Login Hint Strategy**: * Calls `_setLoginHint()` to add session ID or UPN for user identification (unless killswitch active). * This ensures the correct account is selected when multiple AAD accounts exist. * * **PoP Token Support**: * When `authenticationScheme === IAuthenticationScheme.POP`: * - Sets `resourceRequestUri` to target endpoint * - Sets `authenticationScheme` to PoP * - Includes `resourceRequestMethod` (GET, POST, etc.) * - Includes `shrNonce` (nonce from resource server) * - Includes `shrClaims` (additional PoP claims) * * **Used by**: `_loginRedirect()` for full-page authentication * * @param requestContext - The request context. * @returns An MSAL RedirectRequest object. */ private _generateLoginRedirectRequest; /** * This method is used to retrieve the callback for the onRedirectNavigate option on MSAL RedirectRequests. * If this method returns false, then MSAL will cancel the redirect. This method raises an event * that gives the method requesting a token the opportunity to cancel the redirect. * * Note: This method returns a method in order to correctly bind 'this'. If * onRedirectNavigateCallback was a class-level method and included * in a RedirectRequest as a parameter, 'this' fails to bind and * throw a runtime error. * * @returns Returning callback for the onRedirectNavigate option. */ private _getOnRedirectNavigate; /** * Retrieves the current user account from MSAL cache using multiple lookup strategies. * * **Purpose**: * Finds the correct account for the current user from MSAL's cache. When multiple accounts * are cached (multi-user scenarios), this ensures the right account is selected based on * the configured user principal name and AAD user ID. * * **Account Lookup Strategy (priority order)**: * 1. **By username** - Uses `userPrincipalName` from configuration (most reliable for user identity) * 2. **By local ID** - Uses `aadUserId` from configuration (fallback if UPN not available) * 3. **Active account** - Uses currently active account in MSAL (last authenticated account) * * **Active Account Management**: * If an account is found but no active account is set, automatically sets the found account * as active for subsequent operations. This ensures `acquireTokenSilent()` uses correct account. * * **User Switch Detection**: * Detects when configured user (UPN/localId) differs from cached active account: * - Clears redirect state from previous user (prevents redirect loops) * - Logs `MsalBrowserV3TokenProvider.UserSwitchDetected` QoS event * - Clears active account to force reauthentication for new user * - Returns `undefined` to signal account not found (triggers SSO silent or redirect) * * **Return Behavior**: * - Returns account if found by username, localId, or active account * - Returns `undefined` if specific user configured but not found (triggers authentication) * - Returns active account as fallback if no specific user configured * * **Used by**: * - `_generatePopupRequest()`: Sets account for popup authentication * - `_generateSilentRequest()`: Sets account for silent token acquisition * - `_isCurrentUserLoggedInToMsal()`: Checks if user has active session * * @returns An MSAL AccountInfo object of the currently logged in user or undefined if there is no * logged in user. */ private _getCurrentAccount; /** * This method is used to cancel redirects. It is binded to an event raised before full page redirects * so that the method requesting a token may choose to cancel the redirect if necessary by calling this. * By default redirects are turned on. */ private _cancelRedirect; /** * This method returns whether or not a given error is a retriable network related error. * * @param error - An MSAL error code. * @returns Whether or not the error is network related. */ private _isRetriableNetworkError; /** * Using the userPrincipalName from the configuration object, returns whether or not the user is logged * into the MSAL framework. * * @returns True if the current user is logged into the MSAL framework. */ private _isCurrentUserLoggedInToMsal; /** * Using the configuration object passed to the token provider, assembles and returns the 'authority' string * to be used in MSAL requests. * * @returns The 'authority' string to be used in MSAL requests. */ private _getAuthority; /** * Using the userPrincipalName from the configuration object passed to the token provider, returns the * 'upn' string to be used in MSAL requests. * * @returns The 'loginHint' string to be used in MSAL requests. */ private _getUPN; /** * Given the resource a token is being requested for, returns the 'scopes' array to be used in MSAL * requests. Scopes are always returned as a single string in an array, where the scope requested is the * default scope. * * This scope will provide access to all preauthorized scopes and does not provide granular scope access. * * Example: * resourceEndpoint: contoso.sharepoint.com * returns: ['contoso.sharepoint.com/.default'] * * @param resourceEndpoint - The resource a token is being requested for * @returns A scope array to be used with MSAL requests for the given resource. */ private _getScopes; /** * Using the aadSessionId from the configuration object passed to the token provider, returns the 'sid' * string to be used in MSAL requests. If the session ID is not a valid GUID or does not exist, this * will return undefined. * * Note: A value of undefined may result in requiring a full page redirect. * * @returns The 'sid' field to be used in MSAL requests or undefined. */ private _getSessionId; /** * Using the servicePrincipalId from the configuration object passed to the token provider, returns the * 'clientId' string to be used in MSAL requests. * * @returns The 'clientId' field to be used in MSAL requests. */ private _getClientId; /** * Using the redirectUri from the configuration object passed to the token provider, returns the * 'redirectUri' string to be used in MSAL requests. * * @returns The 'redirectUri' field to be used in MSAL requests. */ private _getRedirectUri; /** * Logger for debugging. If the query string parameter 'msalLogging=true' is present, * logs will be printed to the console. */ private _logger; /** * to convert auth scheme of IAuthenticationScheme to AuthenticationScheme */ private _getAuthenticationScheme; private _updatePageEndVisibility; /** * Measures and logs the reliability of full-page redirect authentication flow completion. * * **Purpose**: * Called after a full-page redirect returns to measure how quickly the user completes the * redirect flow. This metric helps track authentication UX and identify slow redirects that * may indicate issues with AAD, network latency, or browser behavior. * * **When Called**: * - By `_ensureTelemetry()` when `CURRENT_REDIRECT_START_TIME_SESSION_STORAGE_KEY` exists in sessionStorage * - Called once per page load after redirect returns * - Automatically invoked before token acquisition begins * * **Measurement Logic**: * 1. Reads redirect start time from sessionStorage (set by `MsalRedirectManager.prepareForRedirect()`) * 2. Calculates time elapsed between redirect start and current time * 3. Compares elapsed time against success window (`SUCCESSFUL_REDIRECT_TIMEFRAME` = 10 seconds) * 4. Logs success if within window, unexpected failure if outside window * 5. Clears tracking data from sessionStorage to prevent duplicate logging * * **Success Window**: * - **Within 10 seconds**: Logged as success (expected redirect completion time) * - **After 10 seconds**: Logged as unexpected failure (slow redirect) * - May indicate: Network latency, AAD delays, slow user interaction, browser issues * - Error name: `RedirectOccurredAfterTimeRange` * * **Monitored Operations**: * - Monitor name: `MsalBrowserV3TokenProvider.fullPageRedirect` * - Success: Redirect completed within 10 seconds * - Unexpected failure: Redirect took longer than 10 seconds * * **Telemetry Data**: * - `timeElapsed`: Milliseconds between redirect start and return * - `CorrelationId`: Tracking ID from original token request (stored in sessionStorage) * - `alias`: 'false' (indicates not a cache hit) * - `isInternal`: true (internal MSAL operation) * * **SessionStorage Keys Used**: * - `CURRENT_REDIRECT_START_TIME_SESSION_STORAGE_KEY`: Redirect start timestamp * - `CORRELATION_ID_SESSION_STORAGE_KEY`: Original request correlation ID * * **Cleanup**: * Removes both sessionStorage keys after logging to prevent: * - Duplicate logging on subsequent page loads * - Stale redirect tracking data accumulation */ private _monitorFullPageRedirectReliability; private _isResourceEndpointExpired; } //# sourceMappingURL=MsalBrowserTokenProvider.d.ts.map