authts / react-oidc-context

Lightweight auth library based on oidc-client-ts for React single page applications (SPA). Support for hooks and higher-order components (HOC).
MIT License
716 stars 68 forks source link

React SPA - Unable to logout user #1214

Open tejasmudholkar opened 7 months ago

tejasmudholkar commented 7 months ago

I have a react application where I have integrated OIDC connect through react-oidc-context referring to installation instructions with some additions. I can Sign the user in the application. Doing so redirects me to the OIDC Sign-In screen, I fill in credentials, and then I am redirected back to my React SPA and my access token is available. All good so far. However, clicking Sign Out I am redirected to OP /logout. If I then navigate back in the browser I again get logged in without asking for credentials but if I refresh the screen then I get logged out.

Can you please help me with this?

My OIDC configuration

import { WebStorageStateStore } from "oidc-client-ts";

export const oidcConfig = {
 authority: window.ENV.AUTHORITY,
 client_id: window.ENV.CLIENT_ID,
 response_type: "code",
 scope: "openid offline groups builder.access",
 redirect_uri: `${window.location.origin}/callback`,
 post_logout_redirect_uri: `${window.location.origin}/logout`,
 automaticSilentRenew: false,
 revokeTokenTypes: ["access_token", "refresh_token"],
 revokeTokensOnSignout: true,
 userStore: new WebStorageStateStore({ store: window.sessionStorage }),
};

Here is my Login file

import { useAuth } from "react-oidc-context";
import "./Login.scss";
import Layout from "./Layout";
import { DefaultRoute } from "../routes";

export const Login = () => {
 const auth = useAuth();

 if (auth.error) {
  return (
   <div className="error">
    Oops something went wrong...
    <p>
     Refresh the browser and try again <br />
     <code> {auth.error.message}</code>
    </p>
   </div>
  );
 }

 if (auth.isLoading) {
  return <div className="loading">Loading...</div>;
 }

 if (auth.isAuthenticated) {
  return (
   <Layout>
    <DefaultRoute />
   </Layout>
  );
 } 

 if (!auth.isAuthenticated) {
  auth.signinRedirect();
 }

 return <></>;
};

export default Login;

Logout method to logout user

import { useAuth } from "react-oidc-context";

export const Logout = () => {
  const auth = useAuth();

  const handleLogout = () => {
    auth.removeUser();
    auth.signoutRedirect();
  };

  return (
    <>
      <button onClick={handleLogout}>Log Out user </button>
    </>
  );
};

I tried adding revokeTokenTypes: ["access_token", "refresh_token"], revokeTokensOnSignout: true properties in the oidc config file, but it didn't work. I expect the user to be logged out after logging out, and if he clicks the browser back button, he should not be led back to the application, but rather remain on the login screen.

pamapa commented 7 months ago

auth.removeUser(); returns a Promise, which you ignore, fixing that might solve your issue

tejasmudholkar commented 6 months ago

Hi, @pamapa Thank you for responding. Could you please provide me with any references for the implementation you have suggested? It would be quite beneficial to me. Also, if I use this method:

  const handleLogout = () => {
    auth.removeUser();
    auth.signoutRedirect();
  };

I'm receiving the following error:

The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Logout failed because query parameter post_logout_redirect_uri is set but id_token_hint is missing.

zach-betz-hln commented 6 months ago

Your current code results in race between auth.removeUser() vs auth.signoutRedirect() since both calls return a promise.

You could try running the 2nd call only on the success of the first call.

auth
  .removeUser()
  .then(() => {
    void auth.signoutRedirect();
  })
  .catch((error) => {
    // Unable to remove user...
  });
dszy579 commented 6 months ago

Hi, @tejasmudholkar I'm experiencing the same issue. Did you manage to solve this issue?

tejasmudholkar commented 6 months ago

Hi, @tejasmudholkar I'm experiencing the same issue. Did you manage to solve this issue?

Hi @dszy579 I did something similar, and it solved my problem.

const { user, removeUser, signoutRedirect, clearStaleState } = useAuth();

 const handleLogout = () => {
    removeUser();
    signoutRedirect({
      id_token_hint: user?.id_token,
    });
    clearStaleState();
  };