We are using MSAL.js to authenticate users to our Azure AD B2C instance. Users can be using a local account or sign in using their credentials from another Azure Active Directory instance.
Having signed in, our SPA gets an access token using acquireTokenSilent, with a fallback to acquireTokenPopup.
What we have noticed is that when acquireTokenSilent times out, the token may still be retrieved in the background, and the application local storage is updated with the token. However, in the app we have proceeded to call acquireTokenPopup. After the user enters their credentials in acquireTokenPopup, the popup displays "Bad Request". The user can close the popup and if they refresh the app, they will now be signed in.
This experience is not a great experience for our users.
Just wondering if this is this a known issue or is expected behavior?
Here is the relevant extract from our code. We wrap the UserAgentApplication in an MsalAuthenticationManager object.
function getMsalAuthenticationManager(authority: IMSALAuthorityConfig): IMsalAuthenticationManager {
return new MsalAuthenticationManager(
appConfig.msal.clientId,
authority.signUpOrSignInAuthority,
authority.passwordResetAuthority,
{
loadFrameTimeout: 15000,
endPoints: endPointsMap,
cacheLocation: appConfig.msal.cacheLocation // localStorage
}
);
}
// MsalAuthenticationManager constructor
constructor(
private applicationId: string,
authority?: string,
authorityForPasswordReset?: string,
msalOptions?: IMsalOptions
) {
var onTokenReceived = authorityForPasswordReset
? (errorDesc: string, token: string, error: string, tokenType: string) => {
// When the user clicks on the forgot password link, the following error is returned to this app.
// In this case we need to re-instantiate the UserAgentApplication object with the Password Reset policy.
if (errorDesc && errorDesc.indexOf("AADB2C90118") > -1) {
this._msal = new UserAgentApplication(
applicationId,
authorityForPasswordReset,
onTokenReceived,
msalOptions
);
this.signIn();
}
}
: (errorDesc: string, token: string, error: string, tokenType: string) => {};
this._msal = new UserAgentApplication(applicationId, authority, onTokenReceived, msalOptions);
this.acquireToken = this.acquireToken.bind(this);
this.signIn = this.signIn.bind(this);
this.signOut = this.signOut.bind(this);
this.getResourceForEndpoint = this.getResourceForEndpoint.bind(this); // Gets the scope for a particular endpoint
this.acquireToken = this.acquireToken.bind(this);
}
public acquireToken(scopes: string[]): Promise<string> {
return new Promise((resolve, reject) => {
this._msal
.acquireTokenSilent(scopes)
.then((accessToken: string) => resolve(accessToken))
.catch((acquireTokenSilentError: string) => {
this._msal
.acquireTokenPopup(scopes)
.then((accessToken: string) => resolve(accessToken))
.catch((acquireTokenPopupError: string) => reject(acquireTokenPopupError));
});
});
}