2
votes

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));
        });
    });
  }
1
Can you post your code please?Jamie Lupton
Updated the post with the relevant snippet of code.mlinehan17

1 Answers

1
votes

I had a similar issue, the reason being the token is still there but expired, and as msal.js doesn t check token expiration, you ll be seen as logged, but your token is actually invalid and your httpRequests with the bearer will fail as unauthorized. you should log the acquiretokenSilent error and look for "AADB2C90077" error, if the token is expired, call for a logout().