Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite redirect loops #1719

Open
jochen-lise opened this issue Oct 24, 2024 · 6 comments
Open

Infinite redirect loops #1719

jochen-lise opened this issue Oct 24, 2024 · 6 comments

Comments

@jochen-lise
Copy link

Hello, we are getting redirect loops on our local developer machines. We use react-oidc-context and oidc-client-ts in combination with Keycloak. I could track it down to the monitorSession flag. if this flag is true, we get the redirect loop as auth.isAuthenticated turns "false" for unknown reason.

For unknown reason as well, this is only in Chrome (v129+) but not in Chrome Incognito Mode or i.e. Firefox. It also is only on localhost and not on our Staging or Prod env.

It is a persistent problem on multiple developer machines (Windows & Mac) and resetting / deleting cache, cookies, storages does not help.

We did update to Keycloak v26 yesterday, but as other browsers are not affected, i think that is a cold trace.

Any ideas what the problem is or what we can try to figure this one out?

import { Log, UserManager } from 'oidc-client-ts';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { AuthProvider, AuthProviderProps } from 'react-oidc-context';
import { BrowserRouter } from 'react-router-dom';
import AuthenticationContext from './authentication/KeycloakAuthenticationContext.tsx';
import getEnvVar from './getEnvVar.ts';
import './index.css';
import './localization/i18n.ts';
Log.setLogger(console);

const oidcConfig: AuthProviderProps = {
  authority: getEnvVar('VITE_OICD_AUTHORITY'),
  client_id: getEnvVar('VITE_OICD_CLIENT_ID'),
  redirect_uri: window.location.origin + window.location.pathname,
};

export const userManager = new UserManager({
  authority: getEnvVar('VITE_OICD_AUTHORITY'),
  client_id: getEnvVar('VITE_OICD_CLIENT_ID'),
  redirect_uri: window.location.origin + window.location.pathname,
  monitorSession: true,           // ** if true: infinite loading loop, if false: no loops**
});

ReactDOM.createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <AuthProvider {...oidcConfig} userManager={userManager}>
      <BrowserRouter>
        <AuthenticationContext>Hello</AuthenticationContext>
      </BrowserRouter>
    </AuthProvider>
  </StrictMode>,
);
import { CircularProgress, Grid, Typography } from '@mui/joy';
import { ReactNode, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { hasAuthParams, useAuth } from 'react-oidc-context';
import { Navigate } from 'react-router-dom';

interface AuthenticationContextProps {
  children: ReactNode | ReactNode[];
}

const AuthenticationContext = (props: AuthenticationContextProps) => {
  const auth = useAuth();
  const { t } = useTranslation();
  const [hasTriedSignin, setHasTriedSignin] = useState(false);

  useEffect(() => {
    const a = hasAuthParams();
    const b = auth.isAuthenticated;  //** for whatever reason this turns to false -> redirect**
    const c = auth.activeNavigator;
    const d = auth.isLoading;
    const e = hasTriedSignin;

    if (!a && !b && !c && !d && !e) {
      auth.signinRedirect();
      setHasTriedSignin(true);
    }
  }, [auth, hasTriedSignin]);

  if (auth.error) {
    console.error(auth.error.message);
    console.error(auth.isAuthenticated);
    console.error(auth.error);
  }

  if (auth.isLoading) {
    return (
      <Grid
        container
        direction="column"
        justifyContent="center"
        sx={{ minHeight: '50vh' }}
      >
        <Grid
          container
          direction="column"
          alignItems="center"
          justifyContent="center"
        >
          <CircularProgress size="lg" />
          <Typography>{t('Loading')}</Typography>
        </Grid>
      </Grid>
    );
  }

  if (!auth.isAuthenticated) {
    return <Navigate to="/" />;
  }

  return <>{props.children}</>;
};

export default AuthenticationContext;
@pamapa
Copy link
Member

pamapa commented Oct 24, 2024

monitorSession: true,           // ** if true: infinite loading loop, if false: no loops**

I guess the monitorSession does no loner work in your Keycloak/Chorme v129+ case for unknown reasons. Try enabling logging of this library.
The affected code is here: https://github.com/authts/oidc-client-ts/blob/main/src/SessionMonitor.ts. In _callback you can see the _raiseUserSignedOut calls. react-oidc-context listens on that events...

@zach-betz-hln
Copy link

Hi @jochen-lise - I tried reproducing this in the sample repo, which uses monitorSession, Keycloak 26.0.2, and I used Chrome 130.x, but was unable to.

In addition to the debug logging that @pamapa mentioned, could you try reproducing your issue in that sample repo please?

@jochen-lise
Copy link
Author

Hello, thank you very much! I can reproduce it when i connect the react app via the env vars to our v26.0.0 Keycloak.

Screen.Recording.2024-10-25.at.11.25.54.mov

When i try to start the sample app with docker compose etc and without changes i get an error. I could not figure out what the problem is.
Screenshot 2024-10-25 at 11 33 21

Either way, I think it looks like that indeed our v26.0.0 could be part of the issue. I checked the changelog but for me, there was nothing obvious that could cause this problem. We will soon update to v26.0.2 and hope that this will fix the problem.

@zach-betz-hln
Copy link

Interesting. I dropped my kc version down from 26.0.2 to 26.0.0 but was still not able to reproduce with the included react sample app.

Reviewing your original snippet, I wonder about this block, if it's causing the infinite loop, since if not auth'd then redirect to home, which will check if not auth'd, then again and again.

if (!auth.isAuthenticated) {
  return <Navigate to="/" />;
}

Could you try changing it to something like this, without the redirect, just to see what happens?

if (!auth.isAuthenticated) {
  return <div>Unable to sign in</div>;
}

@zach-betz-hln
Copy link

When i try to start the sample app with docker compose etc and without changes i get an error. I could not figure out what the problem is.

If you open an issue on the sample app repo with your error details, I'd be glad to look into it with you.

@42tg
Copy link

42tg commented Dec 11, 2024

I also experienced this issue but instead of this happening on Chrome its happens on Firefox only.

As I debugged this it seems that the Authentication is first up fine until the Page loads, but then I get a state update from useAuth() where both Properties isLoading and isAuthenticated are false wich in our case then triggert the signinRedirect().

When I set the mentioned flag monitorSession to false it works fine and I keep it currently like it is.

We are using

"oidc-client-ts": "^3.1.0",
"react-oidc-context": "^3.2.0"

currently just for reference.

Sadly I also cannot affort an small example repository to reproduce this, but maybe this helps anyone in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants