Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Race condition in cache initialization causes intermittent token claim loss under slower conditions after migration to v4 #7561

Open
2 tasks
ocindev opened this issue Feb 6, 2025 · 3 comments
Labels
bug-unconfirmed A reported bug that needs to be investigated and confirmed msal-browser Related to msal-browser package msal-react Related to @azure/msal-react Needs: Attention 👋 Awaiting response from the MSAL.js team public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.

Comments

@ocindev
Copy link

ocindev commented Feb 6, 2025

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

4.2.0

Wrapper Library

MSAL React (@azure/msal-react)

Wrapper Library Version

3.0.4

Public or Confidential Client?

Public

Description

I may have identified a significant race condition in MSAL's cache initialization process that leads to intermittent loss of token claims, particularly under slower processing conditions. The issue manifests when the cache access attempts occur before the initialization process (including decryption) completes fully. This timing-sensitive behavior causes authentication problems that are especially noticeable in Firefox and under constrained CPU conditions.

Error Message

No response

MSAL Logs

Trace Level Logs:
chrome-msal-issue.log
chrome-for-testing-4x-throttle-issue.log
firefox-msal-issue.txt

Network Trace (Preferrably Fiddler)

  • Sent
  • Pending

MSAL Configuration

auth: {
            clientId: publicRuntimeConfig.azureAdClientId,
            authority: publicRuntimeConfig.azureAdAuthority,
            navigateToLoginRequestUrl: false,
            protocolMode: ProtocolMode.OIDC,
        },
        cache: {
            cacheLocation: BrowserCacheLocation.LocalStorage,
            secureCookies: true,
        },
        system: {
            loggerOptions: {
                logLevel: LogLevel.Trace,
                loggerCallback: (level, message, containsPii) => {
                    if (containsPii) {
                        return;
                    }
                    switch (level) {
                        case LogLevel.Error:
                            console.error(message);
                            return;
                        case LogLevel.Info:
                            console.info(message);
                            return;
                        case LogLevel.Verbose:
                            console.debug(message);
                            return;
                        case LogLevel.Warning:
                            console.warn(message);
                            return;
                        default:
                            console.log(message);
                            return;
                    }
                }
            }
        }

Relevant Code Snippets

Reproduction Steps

Next.js 14 Sample
Steps to reproduce are listed as part of its README.md

Expected Behavior

  1. Cache initialization, including all cryptographic operations (base64 decode, HKDF generation, decryption), completes fully
  2. Only after initialization is complete should any cache access attempts be allowed
  3. Token claims should be consistently available after successful authentication, regardless of browser or system performance

Identity Provider

Entra ID (formerly Azure AD) / MSA

Browsers Affected (Select all that apply)

Firefox, Chrome

Regression

@azure/[email protected] @azure/[email protected]

@ocindev ocindev added bug-unconfirmed A reported bug that needs to be investigated and confirmed question Customer is asking for a clarification, use case or information. labels Feb 6, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Attention 👋 Awaiting response from the MSAL.js team label Feb 6, 2025
@github-actions github-actions bot added msal-browser Related to msal-browser package msal-react Related to @azure/msal-react public-client Issues regarding PublicClientApplications labels Feb 6, 2025
@ocindev ocindev changed the title MSAL: Race condition in cache initialization causes intermittent token claim loss under slower conditions after migration to v4 Race condition in cache initialization causes intermittent token claim loss under slower conditions after migration to v4 Feb 6, 2025
@tnorling
Copy link
Collaborator

tnorling commented Feb 7, 2025

As per our initialization docs: "The initialize function is asynchronous and must resolve before invoking other MSAL.js APIs."

Additionally the docs for the useMsal hook specifically mention not relying on claims returned from this object: "Note: The accounts value returned by useMsal will only update when accounts are added or removed, and will not update when claims are updated. If you need access to updated claims for the current user, use the useAccount hook or call acquireTokenSilent instead."

Please use the useAccount hook for account info and ensure the inProgress state is "None" prior to invoking any MSAL APIs.

@tnorling tnorling closed this as completed Feb 7, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Author Feedback Awaiting response from issue author and removed Needs: Attention 👋 Awaiting response from the MSAL.js team labels Feb 7, 2025
@ocindev
Copy link
Author

ocindev commented Feb 7, 2025

Thanks for the quick response @tnorling. I adapted my linked github example accordingly:

import {useAccount} from "@azure/msal-react";
import {handleLogout, handleMsalSilentLogin} from "@/auth/msal";



export default function RootPage() {
    const account = useAccount();

    const handleFetchTokenSilently = async () => {
        const result = await handleMsalSilentLogin();
        console.log('##### Result of silent login', result);
    }

    return (
        <div className="items-center gap-y-2">
            <h2>Active Account</h2>
            <div className="justify-center">
                <span>{JSON.stringify(account, null, 2)}</span>
            </div>
            <div className="flex flex-col items-center gap-y-2">
                <button className="btn btn-primary" onClick={() => handleLogout()}>Logout</button>
                <button className="btn btn-primary" onClick={() => handleFetchTokenSilently()}>Fetch token silently</button>
            </div>
        </div>
    );
}
import {Inter} from "next/font/google";
import {MsalAuthenticationTemplate, useMsal} from "@azure/msal-react";
import {InteractionStatus, InteractionType} from "@azure/msal-browser";
import {msalRedirectRequest} from "@/auth/msal";
import RootPage from "@/components/root";


const Loading = () => <div>Loading...</div>
const Error = () => <div>Error...</div>

function Home() {
    const redirectRequest = msalRedirectRequest();
    const {inProgress} = useMsal();

    if (inProgress !== InteractionStatus.None) {
        return <div>Loading... current status {inProgress}</div>;
    }
    return (
        <main className="container mx-auto w-full">
            <MsalAuthenticationTemplate
                interactionType={InteractionType.Redirect}
                authenticationRequest={redirectRequest}
                loadingComponent={Loading}
                errorComponent={Error}
            >
                <RootPage />
            </MsalAuthenticationTemplate>
        </main>
    );
}


Home.getInitialProps = () => {
    return {}
}

export default Home;

The useAccount MSAL api invocation should now only occur after the inProgress state is InteractionStatus.None.
Though i am still able to reproduce this issue.. A manual use of the acquireTokenSilent API fails with the following error:

_app-174f937c57afd3ff.js:1 Uncaught (in promise) BrowserAuthError: no_account_error: No account object provided to acquireTokenSilent and no active account has been set. Please call setActiveAccount or provide an account on the request.
    at tT (_app-174f937c57afd3ff.js:1:46136)
    at nb.acquireTokenSilent (_app-174f937c57afd3ff.js:7:111675)
    at nO.acquireTokenSilent (_app-174f937c57afd3ff.js:7:117274)
    at u (index-e92370aaba9b696e.js:1:850)
    at e (index-e92370aaba9b696e.js:1:1136)
    at onClick (index-e92370aaba9b696e.js:1:1587)
    at Object.eU (framework-ecc4130bc7a58a64.js:9:14908)
    at eH (framework-ecc4130bc7a58a64.js:9:15062)
    at framework-ecc4130bc7a58a64.js:9:33368
    at re (framework-ecc4130bc7a58a64.js:9:33467)

Still the same steps to reproduce as before + click the Fetch token silently button after the page refresh to trigger the error above.

I also noticed that the event callback for the ACQUIRE_TOKEN_SUCESS event is missing the IdToken after the page refresh as well.

chrome-trace-logs.log

@tnorling tnorling reopened this Feb 7, 2025
@ocindev
Copy link
Author

ocindev commented Feb 11, 2025

As there is still the Needs: Author Feedback label assigned, is there anything you need from my side ?

In the meantime i was playing around a bit more and was even able to reproduce it with the msal-react nextjs sample provided in this repo.

  1. Just add BrowserCacheLocation.LocalStorage as cacheLocation to the cache configuration to authConfig.js.
cache: {
        cacheLocation: BrowserCacheLocation.LocalStorage,
 },
  1. Use the production build of the Next.js sample.
  2. Use chrome to open the MSAL-React Next.js sample
  3. Login using the redirect option
  4. Open the browser dev tools and check the local storage for the msal.token.keys.<uuid> entry.
  5. The idToken value should contain a reference to the local storage idToken entry
  6. Go to the Performance tab and enable 4x CPU slowdown
  7. Refresh the page using CMD + SHIFT + R
  8. Check the msal.token.keys.<uuid> entry in the local storage again
  9. The reference value for the idToken is gone

From here msal is unable to recover on it's own. Removing the CPU slowdown refreshing the page or even using acquireTokenRedirect does not help. Only a complete logout solves the issue.

Based on that i am pretty sure that not the way we integrated msal cause the issues but a problem directly emerging from the encryption introduced with msal v4.

In case you need anything else, feel free to reach out. I am happy to help wherever i can.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Attention 👋 Awaiting response from the MSAL.js team and removed Needs: Author Feedback Awaiting response from issue author labels Feb 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug-unconfirmed A reported bug that needs to be investigated and confirmed msal-browser Related to msal-browser package msal-react Related to @azure/msal-react Needs: Attention 👋 Awaiting response from the MSAL.js team public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.
Projects
None yet
Development

No branches or pull requests

2 participants