auth0-react: Race condition between isAuthenticated and isLoading (redirects) (react-router-v6)

Hello guys!

We have a application with auth0 and react-router v6 and we stumbled upon something that looks like a race condition with onRedirectCallback

  const ProtectedRoute = withAuthenticationRequired(Component, {
    onRedirecting: () => <OurLoadingPage />,
    loginOptions: {
      acr_values: auth0Config.acrValues,
    }
  });

-----------------------------------------------------------------------------------------------------------


  const Auth0Example = ({ props }) => {
   const navigate = useNavigate();

  const onRedirectCallback = appState => {
    navigate(appState?.returnTo || window.location.pathname);
  };

  return (
    <Auth0Provider
    {...auth0Config}
    redirectUri={window.location.origin}
    onRedirectCallback={onRedirectCallback}
    >
    {children}
  </Auth0Provider>
  )
}

This causes us to have a infinite login loop because isLoading is set to false and isAuthenticated is not yet true. (cookie not yet set)

If we add

  const onRedirectCallback = appState => {
  setTimeout(navigate(appState?.returnTo || window.location.pathname), 3000);
};

It will work. (this is not a option because we dont want timeouts in our code)

Or if we remove the onRedirectCallback, but then it wont navigate correctly. (get a blank page without the rendering of component)

isLoading TRUE isAuthenticated FALSE
isLoading FALSE isAuthenticated FALSE
isLoading FALSE isAuthenticated TRUE

Should there be a flag that hold the state of a cookie is set or not before redirecting?

also noted here:

https://github.com/auth0/auth0-react/issues/82#issuecomment-672853184

Thanks in advance. And have a lovely day 😃

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 7
  • Comments: 24 (2 by maintainers)

Most upvoted comments

Thanks for providing the example repro @dalecarslaw

I can confirm the issue, when the user returns to the app after login I’m seeing an unexpected state of isAuthenticated: false , isLoading: false

This looks like it’s caused by the new behaviour of React 18 that double invokes things like setState in StrictMode to detect unexpected side effects (see https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects)

This will only happen in development mode, and the workaround for now is to not use StrictMode - I can confirm that the example app @dalecarslaw shared works as expected if I remove the <StrictMode> component here https://github.com/dalecarslaw/auth0-issue/blob/master/src/index.tsx#L12

I’ll prepare a fix as soon as I can and update this thread when it’s available

Facing this same issue, ended up here after reading through https://github.com/auth0/auth0-react/issues/82

We’ve tried all suggested ā€œsolutionsā€ but nothing has worked for us. Private repo so unfortunately I cannot share the code base.

My work around is checking the cookie set by auth0 rather than relying on isAuthenticated. I think it causes an extra redirect but it seems to work, at least for my app

Experiencing the same issue where isLoading is false but isAuthenticated is also still false and becomes true after. I’m doing this inside of a useEffect similar to @awdyson

Created a repo using CRA to show example here

Also worth mentioning - this only happens after the redirect. Refreshing the page with a logged in account works as expected.

Initial redirect after logging in with google: Screenshot 2022-04-20 at 15 33 47

Then after I refresh the page: Screenshot 2022-04-20 at 15 34 07

I was running into the exact same issue. When I refreshed the page it would always log my user out and this condition would be true even though my user was technically supposed to still be logged in

  // user is not logged in
  if (!isAuth0Loading && !isAuthenticated) {
    return redirectToLoginPage({ returnToOrigin: true });
  }

This seems like a major bug

I fixed it by seeing the cacheLocation to localStorage:

const Auth0ProviderWithRedirectCallback = ({
  children,
}: {
  children: JSX.Element;
}) => {
  const navigate = useNavigate();
  const onRedirectCallback = (appState?: Record<string, string>) => {
    navigate(appState?.redirectPath || RootRoutes.home());
  };

  return (
    <Auth0Provider
      ...
      cacheLocation="localstorage" <-----------------------------
    >
      {children}
    </Auth0Provider>
  );
};

Now when I refresh, my user stays logged in and my if statement is no longer ran

I haven’t gotten around to testing if strict mode helps. Will leave myself a reminder for tomorrow morning though!

@adamjmcgrath Can’t believe I forgot to mention this earlier, sorry! My project is on React 17 and react-router v5.

Will test out the prod build, and with(out) strict and update this comment.

I have a similar issue, but I don’t know if this is because react 18 or react-location (we have another app with react 17 and reac-router v5 which works perfectly fine).

So instead of using withAuthenticationRequired, I did the following work-around (inspired from above comments - thank you all ^^):

  useEffect(() => {
    ;(async () => {
      try {
        // There's a race condition somewhere: the user is not authenticated immediately
        // See https://github.com/auth0/auth0-react/issues/343
        await new Promise(r => setTimeout(r, 1000)) // sleeping 1s seems fine
        await getAccessTokenSilently()
      } catch (e) {
        loginWithRedirect()
      }
    })()
  }, [getAccessTokenSilently, loginWithRedirect])

Same issue with a useEffect approach, and same solution.

image

Hello and thanks for the reply. Will do 😃

I have a similar case — along with onRedirectCallback={(appState) => { navigate(appState?.returnTo || window.location.pathname, { replace: true }); }} I also have a redirect from root to a protected route (i.e. <Route element={<Navigate replace={true} to={{ pathname: "/hives" }} />} exact={true} path="/" />) deeper in the components tree within the component that isn’t rendered up until isLoading is true. However, when the flag indeed becomes true and the aforementioned redirect happens, more often than not the user is not authenticated yet, so withAuthenticationRequired that protectes the /hives route redirects to the login dialog, from there returns to /?code=...&state=..., and before auth0-react can authenticate the user the Navigate to the protected route is being rendered again and, given that the user is not authenticated, it goes to the login dialog again. So it seems like I cannot rely on isLoading flag as an indication that the user has been correctly processed šŸ¤”. If I remove the redirect from / to /hives it all works, tho.