Search code examples
reactjsauthenticationoauth-2.0openid-connectreact-admin

OIDC login flow breaks in react strict mode for react-admin v5


I was using react-admin v4 and built a custom AuthProvider with the help of the oidc-client package and it worked in development (with react StrictMode on) as well as production.

Now, I have upgraded to react-admin v5 and on development the handleCallback method that I attach to the OIDCUserManager.signinRedirectCallback is called twice and the second time it fails because the state was already consumed and I see a page with this text:

Something went wrong No matching state found in storage

I assume, that StrictMode leads to a double trigger of the handleCallback method, because if I remove it it works flawlessly.

Here's the callback method:

  async handleCallback() {
    const query = window.location.search;
    if (!query.includes("code=") && !query.includes("state=")) {
      throw new Error("Failed to handle login callback.");
    }
    await OIDCUserManager.signinRedirectCallback();
  }

Is this something that react-admin should fix or can I do something in my part of the code?


Solution

  • React-admin core team member here. I confirm this is something react-admin should fix, and we actually have plans to do so.

    In the meantime, you can use the same workaround as we applied here: https://github.com/marmelab/ra-auth-auth0/pull/17/files#diff-f9459e79b8587b6e7d46b6b31e5364d352dd3ea777c747c00f4d79c12b414197

    Basically, it implies storing the promise in a closure to ensure you only call it once.

    export const Auth0AuthProvider = {
        // ...
        async handleCallback() {
            if (!handleCallbackPromise) {
                handleCallbackPromise = new Promise(async (resolve, reject) => {
                    // Your actual async implementation
                });
            }
            return handleCallbackPromise;
        },
    };
    
    let handleCallbackPromise: Promise<void> | null = null;
    

    Hope this helps.