react-oidc-context icon indicating copy to clipboard operation
react-oidc-context copied to clipboard

Stuck with auth.isLoading = true with previous page action

Open ValGab opened this issue 1 year ago • 12 comments

Hello,

I have a page with several elements and a button that does this action.

<div 
  onClick={() => { auth.signinRedirect({ redirect_uri: window.location.origin + `/path` });  }}               
>

When I click this button, I am redirected to Keycloak to log in. But when I do "Back" with the browser, I'm stuck on my redirect display in my app because auth.isLoading=true and auth.activeNavigator="signinRedirect". I have experienced this problem with Firefox and Edge.

Here is my App.tsx file


const App: React.FC = () => {
  const auth = useAuth();

  switch (auth.activeNavigator) {
    case "signinSilent":
      return (
        <main className="redirect">
          <div>
            <p>Connexion en cours...</p>
            <Loader className="contained" />
          </div>
        </main>
      );
    case "signoutRedirect":
      return (
        <main className="redirect">
          <div>
            <p>Déconnexion en cours...</p>
            <Loader className="contained" />
          </div>
        </main>
      );
  }

  if (auth.isLoading) {
    return (
      <main className="redirect">
        <div>
          <p>Redirection en cours...</p>
          <Loader className="contained" />
        </div>
      </main>
    );
  }

  if (auth.error) {
    return (
      <main className="redirect">
        <div>
          <p>Vous n'êtes plus connecté(e)</p>
          <button
            className="action-btn"
            onClick={() => {
              auth.signinRedirect({ redirect_uri: window.location.href });
            }}
          >
            Se connecter
          </button>
        </div>
      </main>
    );
  }

There is a way to fix it and display my initial page with my button ?

Config :

  • React v18
  • Keycloak

ValGab avatar May 14 '24 07:05 ValGab

Hello, I'm encoutering the same issue right now. I found a workaround by using the performance metrics from the browser to detect a "Back" navigation action. It's just a dirty patch. The prefered behavior would be to have the "isLoading" state set to false when this happens.

useEffect(() => {
    /* react-oidc is stuck in isLoading mode when we trigger login process so we need to reload the Login page if user press the back button */
    const reloadIfPrevious = () => {
      const perfEntry = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
      if (perfEntry.type === 'back_forward') {
        location.reload()
      }
    }
    window.addEventListener('pageshow', reloadIfPrevious)
    return () => {
      window.removeEventListener('pageshow', reloadIfPrevious)
    }
  })

racacax avatar Jul 04 '24 08:07 racacax

I guess the problem comes from here: https://github.com/authts/react-oidc-context/blob/0eb57acfa8ac846dc90fa5294ad6a0b9ea4a992a/src/AuthProvider.tsx#L204-L215

When you click back on your IdP login page, you will not hit the catch or finally case. Thus NAVIGATOR_INIT is still pending. And as the page was previously loaded it does not reload again...

PS: The isLoading property is there to prevent other actions than the ones required for the sign-in process.

pamapa avatar Jul 09 '24 08:07 pamapa

Not able to reproduce here.

I tried to reproduce with the IdP Entra ID. When I clicked on the browser back button on the IdP login page my application reloads. Thus i am not stuck with isLoading. I was using Firefox.

Also notice I have setup due to other reasons a no-caching on my index.html page via response header CacheControl setup in back-end...

pamapa avatar Jul 09 '24 08:07 pamapa

Indeed, with CacheControl set to no-cache, my app reloads no matter what. This is another workaround.

racacax avatar Jul 16 '24 15:07 racacax

Hello! Please tell me if there are any updates on this issue? I ran into the same problem for several react+keycloak/auth0 applications. For our applications, this is only reproduced on browsers on iOS devices.

AnzhelikaKotko avatar Jul 18 '24 10:07 AnzhelikaKotko

Please tell me if there are any updates on this issue? I ran into the same problem for several react+keycloak/auth0 applications. For our applications, this is only reproduced on browsers on iOS devices.

I am not planing to fix this. Also i have not an idea of how i could tackle this nicely without adding hack code... Have you tried the CacheControl thing?

pamapa avatar Jul 18 '24 10:07 pamapa

Hi, @pamapa ! Thank you for your quick response. I'm going to try this. Is it a correct value? <meta http-equiv="cache-control" content="no-cache" />

UPD: just tried to do it, this does not help

AnzhelikaKotko avatar Jul 18 '24 10:07 AnzhelikaKotko

I guess the problem comes from here:

https://github.com/authts/react-oidc-context/blob/0eb57acfa8ac846dc90fa5294ad6a0b9ea4a992a/src/AuthProvider.tsx#L204-L215

When you click back on your IdP login page, you will not hit the catch or finally case. Thus NAVIGATOR_INIT is still pending. And as the page was previously loaded it does not reload again...

PS: The isLoading property is there to prevent other actions than the ones required for the sign-in process.

On the other hand the following code should reset the state on a re-render: https://github.com/authts/react-oidc-context/blob/0eb57acfa8ac846dc90fa5294ad6a0b9ea4a992a/src/AuthProvider.tsx#L231-L255

@AnzhelikaKotko Why is Line 241 dispatch({ type: "INITIALISED", user }); not executed when you click back on the IOS device? E.g. within Windows Chrome it does.

A complete other approach: I just came aware of the setting redirectMethod, which is by default "assign" changing that to "replace" might prevent the back button on the IdP page. See https://authts.github.io/oidc-client-ts/classes/UserManagerSettingsStore.html#redirectMethod

pamapa avatar Jul 18 '24 11:07 pamapa

Hello @pamapa !

Sorry for the long response. I've tried to use redirectMethod with replace, but it's not convenient for my apps, the flow is changed for all browsers in this case.

What you think about this workaround? https://github.com/authts/react-oidc-context/issues/1243#issuecomment-2208375267

Thank you!

UPDATED https://github.com/authts/react-oidc-context/issues/1243#issuecomment-2208375267 this workaround does not work for ios:(

AnzhelikaKotko avatar Jul 22 '24 15:07 AnzhelikaKotko

Hello!

I found a solution for IOS browsers. I'll leave it here just in case someone catches the same

  useEffect(() => {
    const handlePageShow = (event: { persisted: boolean }) => {
      if (event.persisted && isIOS && auth.isLoading) {
        window.location.reload();
      }
    };

    window.addEventListener('pageshow', handlePageShow);

    return () => {
      window.removeEventListener('pageshow', handlePageShow);
    };
  }, []);

and some useful information could be found here https://web.dev/articles/bfcache

Also want to add, that in my case it's not a bug of react-oidc-contex but specific caching behaviour of ios browsers

AnzhelikaKotko avatar Jul 24 '24 15:07 AnzhelikaKotko

It seems to be bigger issue, because for me it also does not work on Windows - Firefox & Edge. So it seems to be library issue not browsers.

Steps to reproduce:

  1. Go to app
  2. Click log in
  3. On login screen click back button in browser
  4. App is showing Loading Auth....
  5. App stuck with that state

That's my code (from official docs example):

export const AuthWrapper: React.FC<Props> = ({ children }) => {
  const auth = useAuth();
  const [hasTriedSignin, setHasTriedSignin] = useState(false);


  // automatically sign-in
  useEffect(() => {
    if (
      !hasAuthParams() &&
      !auth.isAuthenticated &&
      !auth.activeNavigator &&
      !auth.isLoading &&
      !hasTriedSignin
    ) {
      auth.signinRedirect();
      setHasTriedSignin(true);
    }
  }, [auth, hasTriedSignin]);

  if (auth.isLoading)
    return <>Loading Auth.... {JSON.stringify(auth, null, 2)}</>;

  if (auth && auth.isAuthenticated) return children;

  return (
    <p>You are not authenticated...</p>
  );
};

Properties of auth on which browser stuck after going back: "isLoading": true, "isAuthenticated": false, "user": null, "activeNavigator": "signinRedirect",

Firefox Version: 129.0 (64 bits) Edge Version: Version 127.0.2651.86 (Official build) (64-bit) Microsoft Edge updates are managed by your organization.

brt0555 avatar Aug 14 '24 12:08 brt0555

As mentioned here, I can only reproduce this when removing the Cache-Control: no-cache response header where our React index.html file is served.

I know various project setups exist. But for reference, we bundle our React apps with Vite, then serve the static assets with Express. Then we set the Cache-Control: no-cache response header in Express when serving the index.html file.

zach-betz-hln avatar Aug 14 '24 13:08 zach-betz-hln