Here is my current implementation with react-router-dom, oidc-client-ts, react-oidc-context with the keycloak authorization server
With the following library versions
"oidc-client-ts": "^2.2.4",
"react-oidc-context": "^2.2.2",
<Route
path="/protected"
element={
<AuthOidcProvider>
<AuthBarrier>
<AppLayout />
</AuthBarrier>
</AuthOidcProvider>
}
>
<Route path={HOME_PATH} element={<Home />} />
</Route>
The AuthOidcProvider component is used to provide the auth context
interface AuthOidcProviderProps {
children: ReactNode;
}
const AuthOidcProvider: FC<AuthOidcProviderProps> = ({
children,
}): JSX.Element => {
// const navigate = useNavigate();
const oidcConfig = {
redirect_uri: OAUTH2_REDIRECT_URI,
post_logout_redirect_uri: OAUTH2_POST_LOGOUT_REDIRECT_URI,
silent_redirect_uri: OAUTH2_POST_LOGOUT_REDIRECT_URI,
authority: OAUTH2_AUTHORITY,
client_id: OAUTH2_CLIENT_ID,
scope: "openid profile email",
automaticSilentRenew: true,
onSigninCallback() {
// You must provide an implementation of onSigninCallback to oidcConfig to remove the payload
// from the URL upon successful login.
// Otherwise if you refresh the page and the payload is still there, signinSilent - which handles renewing your token - won't work.
console.log("onSigninCallback()");
window.history.replaceState(
{},
document.title,
window.location.pathname
);
},
};
return <AuthProvider {...oidcConfig}>{children}</AuthProvider>;
};
export default AuthOidcProvider;
The AuthBarrier component handles automatic authentication and blocks unauthenticated users
interface AuthBarrierProps {
children: ReactElement;
}
// Automatically sign-in and silently reestablish your previous session, if you close the tab and reopen the application.
const AuthBarrier: FC<AuthBarrierProps> = ({ children }): JSX.Element => {
const auth = useAuth();
// automatically sign-in
useEffect(() => {
if (
!hasAuthParams() &&
!auth.isAuthenticated &&
!auth.activeNavigator &&
!auth.isLoading
) {
auth.signinRedirect();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
auth.isAuthenticated,
auth.activeNavigator,
auth.isLoading,
auth.signinRedirect,
]);
// // inactivity listener
// useEffect(() => {
// // the `return` is important - addAccessTokenExpiring() returns a cleanup function
// return auth.events.addAccessTokenExpiring(() => {
// console.log("Access token expiring...");
// // renew the access token silently
// auth.signinSilent();
// console.log("Access token renewed.");
// });
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [auth.events, auth.signinSilent]);
switch (auth.activeNavigator) {
case "signinSilent":
console.log("signinSilent");
return <div>Signing you in...</div>;
case "signoutRedirect":
console.log("signoutRedirect");
return <div>Signing you out...</div>;
}
if (auth.isLoading) {
return <LoadingAnimation />;
}
if (auth.error) {
console.error(auth.error);
return <LoadingAnimation />;
}
if (!auth.isAuthenticated) {
return <LoadingAnimation />;
}
return <Fragment>{children}</Fragment>;
};
export default AuthBarrier;
When I try to logout with the auth.removeUser(), I am always redirected to the "HOME" page. In the oidcConfig, the post_logout_redirect_uri has no effect
Does anyone have an example to solve this problem?
removeUser()
andsignoutRedirect()
returnPromise<void>
, so you may want toawait
them inside anasync
method (or chain them withthen()
). – Catherincatherina