msal in React SPA – use access token received from AcquireTokenRedirect

All we need is an easy explanation of the problem, so here it is.

I have a React SPA and I’m using msal to authenticate Microsoft users using loginRedirect. After the login, I’m acquiring an access token silently using acquireTokenSilent to call a web API. When acquiring the access token fails and interaction is required, I’m using acquireTokenRedirect.

When I use acquireTokenRedirect, what I see is:
1. The user is redirected to login.microsoftonline.com.
2. A 302 response is returned with Location header that contains the redirect url + the access token.
3. A GET request to my redirect url – my callback gets called.
4. Another redirect to my app root.

This last redirect makes my app to be served again and I lose the access token from the state of the app. In addition, I lost the ability to redirect the user to a specific route.

Getting the access token:

getAccessToken = async () => {
    let accessTokenRequest = { scopes: [...]
    };
    try {
      var accessTokenResponse = await 
      this.authAgent.acquireTokenSilent(accessTokenRequest);
      return accessTokenResponse.accessToken;
    } catch (error) {
      const errorCode = error.name;
      if (errorCode === "consent_required" || errorCode === "interaction_required") {
        await this.authAgent.acquireTokenRedirect(accessTokenRequest);
      }

      throw error;
    }
  };

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

To avoid the extra redirect, what I needed to do is set the “navigateToLoginRequestUrl” param in Auth config to false. This solves my problem.

Method 2

You can also acquire token with a pop-up window. Here are the differences between acquireTokenPopup and acquireTokenRedirect methods.

When you use acquireTokenPopup method, refer to this sample.

const accessTokenRequest = {
    scopes: ["user.read"]
}

userAgentApplication.acquireTokenSilent(accessTokenRequest).then(function(accessTokenResponse) {
    // Acquire token silent success
    // call API with token
    let accessToken = accessTokenResponse.accessToken;
}).catch(function (error) {
    //Acquire token silent failure, send an interactive request.
    if (error.errorMessage.indexOf("interaction_required") !== -1) {
        userAgentApplication.acquireTokenPopup(accessTokenRequest).then(function(accessTokenResponse) {
            // Acquire token interactive success
        }).catch(function(error) {
            // Acquire token interactive failure
            console.log(error);
        });
    }
    console.log(error);
});

When you use acquireTokenRedirect method, you need to register the redirect callback.

function authCallback(error, response) {
    //handle redirect response
}

userAgentApplication.handleRedirectCallback(authCallback);

const accessTokenRequest: AuthenticationParameters = {
    scopes: ["user.read"]
}

userAgentApplication.acquireTokenSilent(accessTokenRequest).then(function(accessTokenResponse) {
    // Acquire token silent success
    // call API with token
    let accessToken = accessTokenResponse.accessToken;
}).catch(function (error) {
    //Acquire token silent failure, send an interactive request.
    console.log(error);
    if (error.errorMessage.indexOf("interaction_required") !== -1) {
        userAgentApplication.acquireTokenRedirect(accessTokenRequest);
    }
});

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply