oidc-client-ts icon indicating copy to clipboard operation
oidc-client-ts copied to clipboard

Infinite redirect loops

Open jochen-lise opened this issue 1 year ago • 10 comments

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;

jochen-lise avatar Oct 24 '24 11:10 jochen-lise