dotnet/aspnetcore · error · Error

Failed to retrieve token, no account found.

Error message

Failed to retrieve token, no account found.

What it means

In the MSAL-backed Blazor WebAssembly authentication service, getTokenCore attempts to acquire an access token silently for the currently signed-in account. If getAccount() returns no account (the user is not signed in / their session was cleared), there is no account to pass to MSAL's acquireTokenSilent, so the service throws. This indicates an authentication-state mismatch: the code reached token acquisition without a signed-in account.

Solutions

  1. Guard token requests behind a signed-in check; trigger an interactive login (loginPopup/loginRedirect) when no account exists.
  2. Handle the thrown error by redirecting the user to authentication, then retrying the token request.
  3. Verify MSAL cache storage (localStorage/sessionStorage) is not blocked by browser privacy settings.
  4. Ensure the auth flow fully completes (await AuthenticationService) before requesting tokens.

Example fix

// before
const token = await authService.getAccessToken(opts);
// after
const status = await authService.getAccessToken(opts);
if (status.status === 'requiresRedirect') {
  await authService.signIn(returnUrl);
  return;
}
// and in MSAL config, fall back to interactive when silent fails:
try { return await msal.acquireTokenSilent(req); }
catch { return await msal.acquireTokenPopup(req); }
Defensive patterns

Strategy: try-catch

Validate before calling

// Before requesting a token, check for an account
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
  // trigger interactive sign-in instead of acquiring silently
  await msalInstance.loginRedirect(loginRequest);
  return;
}

Type guard

function hasAccount(accounts: any[]): boolean {
  return Array.isArray(accounts) && accounts.length > 0;
}

Try / catch

try {
  return await authService.getTokenCore(scopes);
} catch (e) {
  if (/no account found/i.test((e as Error).message)) {
    await msalInstance.loginPopup(loginRequest);
    return await authService.getTokenCore(scopes);
  }
  throw e;
}

Prevention

When it happens

Trigger: Thrown at line 191 when this.getAccount() returns falsy inside getTokenCore, before constructing the silent token request. Triggered by an interactive token request when MSAL has no account in cache.

Common situations: The user's MSAL session expired or was cleared (cache eviction, browser storage wipe); calling token acquisition before login completes; redirect-based auth where the post-redirect account population race lost; same-site/cookie policies blocking the MSAL cache; the user manually signed out but the app still requested a token.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/cfac5b69bca9a741. Report an issue: GitHub.

Appendix: source

Thrown at src/Components/WebAssembly/Authentication.Msal/src/Interop/AuthenticationService.ts:191

    async getAccessToken(request?: AccessTokenRequestOptions): Promise<AccessTokenResult> {
        try {
            this.trace('getAccessToken', request);
            const newToken = await this.getTokenCore(request?.scopes);
            return {
                status: AccessTokenResultStatus.Success,
                token: newToken
            };
        } catch (e) {
            return {
                status: AccessTokenResultStatus.RequiresRedirect
            };
        }
    }

    async getTokenCore(scopes?: string[]): Promise<AccessToken | undefined> {
        const account = this.getAccount();
        if (!account) {
            throw new Error('Failed to retrieve token, no account found.');
        }

        const silentRequest = {
            redirectUri: this._settings.auth?.redirectUri,
            account: account,
            scopes: scopes || this._settings.defaultAccessTokenScopes
        };

        this.debug(`Provisioning a token silently for scopes '${silentRequest.scopes}'`)
        this.trace('_msalApplication.acquireTokenSilent', silentRequest);
        const response = await this._msalApplication.acquireTokenSilent(silentRequest);
        this.trace('_msalApplication.acquireTokenSilent-response', response);

        if (response.scopes.length === 0 || response.accessToken === '') {
            throw new Error('Scopes not granted.');
        }

        const result = {

View on GitHub (pinned to 3600ca084e)