I'm using Keycloak authentication in my React project with the packages react-oidc-context
and oidc-client-ts
. Authentication and API requests work perfectly when logging in, as the access token is correctly retrieved and used.
However, every time I refresh the page, I encounter the following error:
No matching state found in storage
This issue seems related to the way state is managed between sessions or across page reloads.
Below is my current configuration for react-oidc-context
:
const oidcConfig: AuthProviderProps = {
authority: import.meta.env.VITE_OIDC_AUTHORITY,
client_id: import.meta.env.VITE_OIDC_CLIENT_ID,
redirect_uri: window.location.origin,
post_logout_redirect_uri: window.location.origin,
};
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AuthProvider {...oidcConfig}>
<App />
</AuthProvider>
</React.StrictMode>,
);
I expected that after the page refresh, the session and state would be preserved, allowing the app to continue functioning without requiring a re-login.
To resolve this issue, I attempted the following:
Unfortunately, neither approach resolved the problem, and the error persists after a page reload.
After some research and trying different approaches, I resolved the issue by clearing the URL in the onSigninCallback
function. This is necessary because the state
and code
parameters in the URL after the OIDC authentication flow do not match the ones stored in the local or session storage, which triggers an error.
Here’s how I implemented the solution:
const oidcConfig: AuthProviderProps = {
authority: import.meta.env.VITE_OIDC_AUTHORITY,
client_id: import.meta.env.VITE_OIDC_CLIENT_ID,
redirect_uri: window.location.origin,
post_logout_redirect_uri: window.location.origin,
onSigninCallback: () => window.history.replaceState({}, document.title, window.location.pathname),
};
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AuthProvider {...oidcConfig}>
<App />
</AuthProvider>
</React.StrictMode>,
);
By using window.history.replaceState, I remove the state and code parameters from the URL after the sign-in process completes, ensuring there’s no mismatch with the stored values.