question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

handleRedirectCallback not useful in SPA, documentation misleading

See original GitHub issue

Please follow the issue template below. Failure to do so will result in a delay in answering your question.

Library

msal@1.2.1

Framework

React v16, + parcel bundler

Description

The redirect flow handles the return from a redirect in a way that it does an additional navigation to hide the hash and return the user to the page they were on when they redirected. So far this is good.

However… using the handleRedirectCallback only gets called on the first redirect (with the hash) and on the second redirect (to remove the hash) the response is now removed. This means that on a page where such a second navigation happens, the page is reloaded such that the redirect response is no longer available.

What does work is using the silent token acquisition to get the current token as stored by msal from a redirect (e.g. get it if you have it, even if silent acquisition isn’t supported).

This means the doc indicating handleRedirectCallback is either incomplete or incorrect, because the working sample code doesn’t use it to get a token but instead also uses the silent token acquisition to get the most recent state of a token for that request.

In short, you can’t always use handleRedirectCallback as the documentation indicates because it doesn’t actually work when the msal library does the second redirect, but what does work is silent token acquisition, which isn’t documented for the redirect pattern. I’m not entirely sure why the pattern can’t be this instead in practice as its what happens in the working pattern.

token = userAgent.acquireCachedToken(authenticationParams);

This would also avoid the need to deal with the promise part of acquireTokenSilently.

Security

I don’t believe so

Regression

Don’t know, have only ever used this version.

Configuration

Please provide your MSAL configuration options.

const tenantId = 'e3b48527-4cbe-42a2-b4d2-11b3cc7a86fc';
const clientId = '8b1d6b0d-3777-4099-b6bd-6db1ff2ddb02';
const redirectUri = 'http://localhost:1234/';
const apiId = `062da26d-b94e-424d-b119-b6b12fc46618`
const apiUri = `api://${apiId}`;
const scopes = [`${apiUri}/all:full`];

const accessTokenRequest: MSAL.AuthenticationParameters = {
    scopes
};


const msalAppConfig: MSAL.Configuration = {
    auth: {
        clientId,
        authority: `https://login.microsoftonline.com/${tenantId}/`,
        redirectUri
    },
    cache: {
        cacheLocation: 'localStorage'
    }
}

Reproduction steps

export const AuthProvider = (props: React.PropsWithChildren<{}>) => {
    // access token is state as it comes back via a promise.
    const [accessToken, setAccessToken] = React.useState<string>();
    const userAgent = new MSAL.UserAgentApplication(msalAppConfig);

    userAgent.handleRedirectCallback((error, result) => {
        // msal requires a redirect callback, even though can't use it to
        // get the result as it will redirect again after it has the result
        // and not provide the result of the call back on the second
        // redirect.
    });

    function onLogin() {
        userAgent.loginRedirect(accessTokenRequest);
    }

    function onLogout() {
        console.log('clear access token');
        setAccessToken(undefined);
        userAgent.logout();
    }

    async function updateToken() {
        try {
            // silent will renew if possible, but also reply with
            // a token gotten from a redirect workflow.
            const result = await userAgent.acquireTokenSilent(accessTokenRequest);
            if (result && result.accessToken) {
                console.log(`silently acquired token ${result.accessToken}`);
                setAccessToken(result.accessToken);
            }
        } catch (error) {
            console.log(`access token not available`);
        }
    }

    React.useEffect(() => { updateToken(); return; }, []);
    
    const context: AppContext = {
        login: onLogin,
        logout: onLogout,
        accessToken
    };

    return (
        <AppContext.Provider value={context}>
            {props.children}
        </AppContext.Provider>
    );
}

Expected behavior

I expected there to be a clearer way to get the token returned via a redirectLogin that wasn’t invalidated by msal cleaning up the redirect hash and didn’t require redundant caching in the app as its already cached by msal as evident in acquire token silently.

Browsers

Not sure, but does happen in current Chrome. Version 79.0.3945.130 (Official Build) (64-bit)

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:4
  • Comments:17 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
m-sterspacecommented, Mar 2, 2020

I read through that quick start, and it got me up and running with the loginpopup method in a couple of hours, but it doesn’t provide any information on how to properly implement the redirect flow.

For instance this diagram is great: https://docs.microsoft.com/en-us/azure/active-directory/develop/media/quickstart-v2-javascript/javascriptspa-intro.svg … but it doesn’t really make sense with a redirect flow given that the token response is delivered to a different instance of your application then the one that requested it.

It also doesn’t tell you the most critical thing about the redirect method which is where you actually need to put each of those function calls in relation to your app’s lifecycle. For instance the way I had implemented it originally worked, but the last update caused all my sites to break and go into infinite redirect loops because of when my functions were being called. I rewrote it and got it working again, but I still don’t know if I did it the way I’m supposed to because I haven’t been able to find a complete redirect example.

0reactions
m-sterspacecommented, Apr 29, 2020

@tnorling thanks, just upgraded and this is feeling more intuitive already!

Read more comments on GitHub >

github_iconTop Results From Across the Web

appState from client.handleRedirectCallback() gives an error ...
Getting an error Invalid state at client.handleRedirectCallback(), but not always. Code snippet: type AuthenticationState = { initializing: ...
Read more >
Initialize MSAL.js client apps - Microsoft Entra
This article describes initializing the Microsoft Authentication Library for JavaScript (MSAL.js) with an instance of a user-agent application.
Read more >
Failed to get tokens using Azure AD and SPA - Stack Overflow
As superstar @GauravMantri mentioned, if you are developing a SPA, you should use MSAL.js to log ... Call REST API directly not works...
Read more >
Auth0: Vue & TypeScript Quickstart SDK - The Missing Docs
We differ in two substantial way from the original tutorial: We have one less method: handleRedirectCallback is not used anywhere in the ...
Read more >
Persistent login in React using refresh token rotation
Until recently, using refresh tokens was not recommended in ... The following two cases from the Auth0 docs are good examples of the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found