Unable to acquire token silently after B2C login and redirection to SPA redirectUri
See original GitHub issueCore Library
MSAL.js v2 (@azure/msal-browser)
Core Library Version
2.24.0
Wrapper Library
Not Applicable
Wrapper Library Version
None
Description
My understanding is that the B2C flow with MSAL.js for a sign-in only policy works in the following way (please correct if mistaken):
- create
msalInstance
with the msal config - call
msalInstance.handleRedirectPromise()
- when the
handleRedirectPromise
promise returns, callloginRedirect
with the correct scopes, which will redirect the user to a b2c login page, and on completion, navigate back to the SPAredirectUri
- once the the b2c login is complete, and the user is navigated back to the SPA
redirectUri
, we use themsalInstance.acquireTokenSilent
with the correct scopes and current active account passed in as function option params, so we can get all the user information such as theaccessToken
. This is how we translate the information the MSAL stores in the browser (sessionStorage
in this case) to user information and an access token that I can use.
Steps 1-3 are working as expected. The issue is specifically that on step 4, after the redirect happens when I login, I am unable to acquire the token. There are no active accounts (when I attempt to retrieve with MSAL.js), and I am also unable to acquire the token with acquireTokenSilent
. The error I am getting is the following:
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.
The issue is that I can’t call setActiveAccount
when the active account does not exist (nothing exists for msalInstance.getAllAccounts()
.
I am using the following code for step 4 - which is run after the the successful login redirect to the redirectUri
:
const accounts = msalInstance.getAllAccounts();
if (accounts?.length > 0) {
msalInstance.setActiveAccount(accounts[0]);
}
if (msalInstance.getActiveAccount()) {
const msalScopes = { scopes: ["my-example-b2c-web-api-scope"] }
msalInstance
.acquireTokenSilent(msalScopes)
.then((tokenResponse) => {
// Do something with the tokenResponse
console.log('acquireTokenSilent res', tokenResponse);
})
.catch((error) => {
console.log('acquireTokenSilent error', error);
if (error instanceof msal.InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return msalInstance.acquireTokenRedirect(
msalScopes
);
}
});
The issue is that because this.msalInstance.getAllAccounts()
is null
(empty), I cannot successfully retrieve the token information from the acquireTokenSilent
call.
However, if I sign-in the first time, and get navigated back to the redirectUri
, and then I run the sign-in again (the msalInstance.handleRedirectPromise()
and then loginRedirect()
code), I will successfully get the accounts and the token response from acquireTokenSilent
. So I know that it most likely is not a configuration issue, or something to do with scopes or permissions.
The issue that needs to be figured out, is how can the token be retrieved on the successful navigation from the b2c login to the SPA redirectUri
? Having to trigger a sign-in twice is not doable for the app use-case. I am hoping there is a better way to do this and to fix the issue of being able to retrieve the token on that initial redirect navigation to the redirectUri
of the SPA.
The expected behavior is that when the SPA redirectUri
is hit, that I will be able to get the access token and other user information. acquireTokenSilent
doesn’t seem to be working as expected for this use case.
Error Message
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.
Msal Logs
n/a
MSAL Configuration
const msalConfig = {
auth: {
clientId: 'example123',
authority: 'b2c-example',
redirectUri: 'localhost:4200/redirect-uri',
knownAuthorities: ['my-b2c-web-api-scope'],
postLogoutRedirectUri: 'localhost:4200/redirect-uri',
navigateToLoginRequestUrl: true,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: true,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case msal.LogLevel.Error:
console.error(message);
return;
case msal.LogLevel.Info:
console.info(message);
return;
case msal.LogLevel.Verbose:
console.debug(message);
return;
case msal.LogLevel.Warning:
console.warn(message);
return;
}
},
},
},
};
Relevant Code Snippets
// initial code
msalInstance
.handleRedirectPromise()
.then((tokenResponse) => {
if (tokenResponse === null) {
// If the tokenResponse === null, you are not coming back from an auth redirect.
msalInstance.loginRedirect(this.msalApiScopes);
} else {
// If the tokenResponse !== null, then you are coming back from a successful authentication redirect.
console.log('success res', tokenResponse);
}
})
.catch((err) => {
// handle error, either in the library or coming back from the server
console.log('err', err);
});
// code that runs after the redirectUri returns
const accounts = msalInstance.getAllAccounts();
if (accounts?.length > 0) {
msalInstance.setActiveAccount(accounts[0]);
}
const msalScopes = { scopes: ["my-example-b2c-web-api-scope"] }
msalInstance
.acquireTokenSilent(msalScopes)
.then((tokenResponse) => {
// Do something with the tokenResponse
console.log('acquireTokenSilent res', tokenResponse);
})
.catch((error) => {
console.log('acquireTokenSilent error', error);
if (error instanceof msal.InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return msalInstance.acquireTokenRedirect(
msalScopes
);
});
Reproduction Steps
see initial description
Expected Behavior
Be able to get token through acquireTokenSilent
method directly after the redirect back to the SPA redirectUri
after the b2c login is completed. Not having to go through the handleRedirectPromise
a second time
Identity Provider
Azure B2C Basic Policy
Browsers Affected (Select all that apply)
Chrome
Regression
No response
Source
External (Customer)
Issue Analytics
- State:
- Created a year ago
- Comments:14 (13 by maintainers)
Top GitHub Comments
@danielvoigt I am currently looking into this , thanks for your patience!
@danielvoigt This issue has been automatically marked as stale because it is marked as requiring author feedback but has not had any activity for 5 days. If your issue has been resolved please let us know by closing the issue. If your issue has not been resolved please leave a comment to keep this open. It will be closed automatically in 7 days if it remains stale.