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

React SPA - Unable to logout user

Open tejasmudholkar opened this issue 1 year ago • 11 comments

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.

tejasmudholkar avatar Apr 24 '24 09:04 tejasmudholkar

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

pamapa avatar Apr 24 '24 10:04 pamapa

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.

tejasmudholkar avatar Apr 29 '24 06:04 tejasmudholkar

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...
  });

zach-betz-hln avatar May 02 '24 17:05 zach-betz-hln

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

dszy579 avatar May 15 '24 06:05 dszy579

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();
  };

tejasmudholkar avatar May 23 '24 04:05 tejasmudholkar