{"record":{"id":"0bfcc1f46c027c9f","repo":"dotnet/aspnetcore","slug":"scopes-not-granted","errorCode":null,"errorMessage":"Scopes not granted.","messagePattern":"Scopes not granted\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Components/WebAssembly/Authentication.Msal/src/Interop/AuthenticationService.ts","lineNumber":206,"sourceCode":"    async getTokenCore(scopes?: string[]): Promise<AccessToken | undefined> {\n        const account = this.getAccount();\n        if (!account) {\n            throw new Error('Failed to retrieve token, no account found.');\n        }\n\n        const silentRequest = {\n            redirectUri: this._settings.auth?.redirectUri,\n            account: account,\n            scopes: scopes || this._settings.defaultAccessTokenScopes\n        };\n\n        this.debug(`Provisioning a token silently for scopes '${silentRequest.scopes}'`)\n        this.trace('_msalApplication.acquireTokenSilent', silentRequest);\n        const response = await this._msalApplication.acquireTokenSilent(silentRequest);\n        this.trace('_msalApplication.acquireTokenSilent-response', response);\n\n        if (response.scopes.length === 0 || response.accessToken === '') {\n            throw new Error('Scopes not granted.');\n        }\n\n        const result = {\n            value: response.accessToken,\n            grantedScopes: response.scopes,\n            expires: response.expiresOn\n        };\n\n        this.trace('getAccessToken-result', result);\n\n        return result;\n    }\n\n    async signIn(context: AuthenticationContext) {\n        this.trace('signIn', context);\n        try {\n            // Before we start any sign-in flow, clear out any previous state so that it doesn't pile up.\n            this.purgeState();","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/WebAssembly/Authentication.Msal/src/Interop/AuthenticationService.ts#L188-L224","documentation":"Thrown by getTokenCore() in the MSAL interop (AuthenticationService.ts:206) when acquireTokenSilent resolves but the response carries no scopes (response.scopes.length === 0) or an empty access token (response.accessToken === ''). MSAL returning an empty scope set or empty token indicates consent was not granted for any of the requested scopes, so the token is unusable; the service treats this as a hard failure rather than returning a useless token.","triggerScenarios":"acquireTokenSilent succeeds but the user/admin has not consented to the requested scopes, or the scopes parameter is empty/invalid, or incremental consent is required. The response object has scopes=[] or accessToken='' after the silent call.","commonSituations":"Requesting API scopes that were never consented to (the app registration does not expose them, or admin consent is required tenant-wide). Mismatch between defaultAccessTokenScopes and what MSAL can actually grant. Conditional Access policies denying the resource. Using the wrong scope URI format (e.g., missing the API App ID URI).","solutions":["Trigger an interactive token acquisition (acquireTokenPopup/Redirect) so MSAL can prompt for consent on the missing scopes.","Verify the requested scopes exactly match scopes exposed/delegated in the app registration (e.g., 'api://<clientId>/access_as_user').","Confirm admin consent is granted for the scopes if the app is configured to require it.","Check defaultAccessTokenScopes in MSAL configuration is non-empty and contains valid scopes."],"exampleFix":"// before — silent only, fails when consent missing\nconst r = await msal.acquireTokenSilent({ scopes: ['api://x/y'], account });\n\n// after — fall back to interactive when silent returns nothing\nlet r = await msal.acquireTokenSilent({ scopes, account }).catch(async () => {\n  r = await msal.acquireTokenPopup({ scopes });\n});","handlingStrategy":"fallback","validationCode":"function hasGrantedScopes(response: any): boolean {\n  return response && Array.isArray(response.scopes) && response.scopes.length > 0 && typeof response.accessToken === 'string' && response.accessToken.length > 0;\n}","typeGuard":null,"tryCatchPattern":"try {\n  r = await msal.acquireTokenSilent({ scopes, account });\n} catch (e) {\n  if (/scopes not granted/i.test(e.message)) {\n    r = await msal.acquireTokenPopup({ scopes }); // interactive consent\n  } else { throw e; }\n}","preventionTips":["Expose and consent to all requested scopes in the app registration.","Provide an interactive fallback when silent acquisition yields no scopes.","Verify scope URI format (api://<appId>/<scope>).","Confirm admin consent when required by policy."],"tags":["authentication","msal","oauth","consent","scopes","blazor"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}