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

Error after Keycloak login "No matching state found in storage"

Open debegr92 opened this issue 11 months ago • 4 comments

I try to use react-oidc-context in a small example project. Most of it based on the code of this README.md. It seems like the onSigninCallback is not working properly and I need a second login to get the correct state, token and user info.

This is the behavior

  1. click login button (call signinRedirect() )
  2. redirected to Keycloak
  3. login with my username/password
  4. redirected back to my app and path /oauth2/callback + parameters in URL
  5. ERROR: "No matching state found in storage"
  6. (at this time, the onSignInCallback was not triggered!)
  7. click on the login button again (call signinRedirect(), exactly like the first time)
  8. without getting redirected a second time to Keycloak, onSigninCallback is triggered and I am logged in!

keycloakConfig.tsx

export const signinCallback = (_user: User | void): void => {
	console.log("onSigninCallback");
	console.log(_user);
	window.history.replaceState(
		{},
		document.title,
		window.location.pathname
	)
}

export const oidcConfig:AuthProviderProps = {
	authority: "http://127.0.0.1:7080/realms/test",
	client_id: "frontend",
	// This redirect URI needs to match exactly your configuration in Keycloak!
	//redirect_uri: "http://127.0.0.1:5173",
	redirect_uri: "http://127.0.0.1:5173/oauth2/callback",
	onSigninCallback: signinCallback
};

main.tsx

import { AuthProvider } from 'react-oidc-context';
import { oidcConfig } from './keycloakConfig.tsx';


createRoot(document.getElementById('root')!).render(
	<StrictMode>
		<AuthProvider {...oidcConfig}>
			<App />
		</AuthProvider>
	</StrictMode>,
)

App.tsx

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

function App() {
	const {isAuthenticated, isLoading, error, user, settings, activeNavigator, removeUser, signinRedirect} = useAuth();
	console.log(settings);

    switch (activeNavigator) {
        case "signinSilent":
            return <div>Signing you in...</div>;
        case "signoutRedirect":
            return <div>Signing you out...</div>;
    }

    if (isLoading) {
        return <div>Loading...</div>;
    }

    if (isAuthenticated) {
        return (
			<div>
				Hello {user?.profile.sub}{" "}
				<p>{JSON.stringify(user)}</p>
				<button onClick={() => void removeUser()}>Log out</button>
			</div>
        );
    }

	return (
		<div>
			{(error ? <div>Oops... {error.message}</div> : <></>)}
			<button onClick={() => void signinRedirect()}>Log in</button>
		</div>
	);
}

debegr92 avatar Feb 14 '25 17:02 debegr92

@debegr92 - We're seeing the same thing with our project, however it works on a local development machine - but not when we deploy to a test server.

Did you have any luck finding a solution?

gidich avatar Feb 27 '25 09:02 gidich

Hi @debegr92 and @gidich - are either of you able to reproduce this error in the keycloak sample repo?

zach-betz-hln avatar Feb 27 '25 14:02 zach-betz-hln

Okay, here is what I did @zach-betz-hln

  1. Clone the repository https://github.com/authts/sample-keycloak-react-oidc-context
  2. cd inside react
  3. Add .env with VITE_AUTHORITY and VITE_CLIENT_ID
  4. change src/config.ts to use my redirect_uri http://127.0.0.1:5173/oauth2/callback
  5. npm install
  6. npm run dev

Same result. First login shows "no matching state".

Image

Logout and login again then works (the default router shows nothing for my callback route, but I can see the home button and my token).

Image

I am using a working Keycloak cloud instance and try to implement the user login on my local machine. So therefore I added the 127.0.0.1 as valid redirect URL in Keycloak.

debegr92 avatar Mar 01 '25 09:03 debegr92

@debegr92 - Interesting. Now I am wondering about the config of your Keycloak cloud instance.

One thing you could try with the sample repo is running it once with default config, then again pointed to your Keycloak cloud instance, and compare the responses in the DevTools Network tab.

Do your usual login/logout flow then compare the responses in each run for relevant differences.

zach-betz-hln avatar Mar 03 '25 14:03 zach-betz-hln