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

Auth context is lost with react router

Open slabiakt opened this issue 1 year ago • 4 comments

Hi, I use react v18, router v6 and this library. Without router everything works as expected however with router i have this problem that when i try to enter protected route /admin directly from browser then auth.isAuthenticated is false, but when I enter this path via <Naviage to="/admin"> then auth.isAuthenticated is still set to true. When I don't use RouteAuthGuard and enter directly to /admin then auth context is resolved from local storage but with RouteAuthGuard it seems that it can't resolve auth from local storage and auth is set to false.

function App() {
  const router = createBrowserRouter([
    {
      path: "/",
      element: <Home />,
    },
    {
      path: "/admin",
      element: <RouteAuthGuard component={<Admin />}></RouteAuthGuard>,
    },
    {
      path: "/callback",
      element: <AuthControl />,
    },
  ]);

  <RouterProvider router={router} />;

  return <RouterProvider router={router} />;
}
export const RouteAuthGuard: React.FC<Props> = ({ component }) => {
  const auth = useAuth();
  const location = useLocation();
  const navigate = useNavigate();
  const context = React.useContext(AuthContext);

  useEffect(() => {
    if (!auth.isAuthenticated) {
      // localStorage.setItem(PATH_LOCAL_STORAGE_KEY, location.pathname);
      navigate("/home");
    }
  }, [auth.isAuthenticated]);

  if (auth.isLoading) {
    return <p>loading!</p>;
  }

  if (auth.error) {
    throw new Error("unauthorized");
  }

  return <>{component}</>;
};
const AuthControl: React.FC = () => {
  const navigate = useNavigate();
  const auth = useAuth();

  useEffect(() => {
    if (auth.isAuthenticated) {
      console.log(auth);
      navigate("/");
    }
  }, [auth.isAuthenticated]);

  if (!auth.isAuthenticated) {
    return <div>Loading...</div>;
  }

  if (auth.error) {
    return <div>Oops... {auth.error.message}</div>;
  }
};

export default AuthControl;
export const oidcConfig = {
  redirect_uri: `${window.location.origin}/callback`,
  post_logout_redirect_uri: window.location.origin,
  authority: "https://euc1.auth.ac/auth/realms/xxxxx",
  client_id: "react-app",
  response_type: "code",
  automaticSilentRenew: true,
  loadUserInfo: true,
  triggerAuthFlow: true,
  userStore: new WebStorageStateStore({ store: window.localStorage }),
};

any idea why?

slabiakt avatar Oct 01 '23 04:10 slabiakt

make sure AuthProvider comes before RouterProvider

pamapa avatar Oct 02 '23 06:10 pamapa

@pamapa I used metadata key in the config to avoid using CORS and also have a redirection problem

export const oidcConfig = {
  authority: GAS_BASE_URL,
  client_id: process.env.REACT_APP_GAS_CLIENT_ID,
  redirect_uri: process.env.REACT_APP_GAS_CALLBACK_URL,
  scope: 'openid profile group_type email',
  onSigninCallback: (user) => {
    console.log('onsignin', user);
    window.history.replaceState({}, document.title, '/');
    window.location.reload();
  },
  userStore: new WebStorageStateStore({ store: window.localStorage }),
  metadata: {
    issuer: GAS_BASE_URL,
    authorization_endpoint: GAS_BASE_URL + '/as/authorization.oauth2',
    userinfo_endpoint: GAS_BASE_URL + '/idp/userinfo.openid',
    end_session_endpoint: GAS_BASE_URL + 'idp/startSLO.ping'
  }
};

log "onsignin" never fires. And in the console there is nothing but a warning: "No routes matched location "/callback?code=F8...78ca17e..asd".

The provider comes before Router:

root.render(
  <AuthProvider {...oidcConfig}>
    <BrowserRouter>
      <Routes>
       ...

any ideas why redirection doesn't happen? Without metadata and with "CORS Unblock" extension everything works fine

UPDATED: Enabled logs and getting

Logger.ts:89 [OidcClient] readSigninResponseState: Error: No matching state found in storage

maybe a configuration is wrong, weird

UPDATED: I added token_endpoint: GAS_BASE_URL + '/as/token.oauth2' parameter, now it's just getting stuck on a callback page with a CORS error to this /as/token.oauth2 URL.

And I'm wondering, is it a bug in this lib or on an SSO authority side? Because in the docs oidc-client-ts it says: just add metadata to solve CORS issue. I added, didn't help :)

ssuvorov avatar Oct 10 '23 16:10 ssuvorov

Logger.ts:89 [OidcClient] readSigninResponseState: Error: No matching state found in storage

That is the redirect callback call and it can somehow not match the data with the previously stored sigin request data, you will need to find out why...

pamapa avatar Oct 16 '23 14:10 pamapa

Did you try using withAuthenticationRequired ? See README

wa1id avatar Mar 01 '24 12:03 wa1id