oidc-client-ts
oidc-client-ts copied to clipboard
Token reappears after logout
After logging out oidc-client-ts
thinks it's still logged in. I suspect that it is hiding data somewhere.
The problem continues if I clear all site data (Firefox) but not in a new private window.
To log out I redirect to IdentityServer to log out there, then that passes back to my React app which does this
if (isServersideLogoutRedirect()) {
setState(currentState => ({ ...currentState, isLoggingOut: true, user: null }));
userManager.current
.removeUser()
.then(() => {
userManager.current.revokeTokens();
})
.then(() => {
userManager.current.clearStaleState();
})
.then(() => {
setState({
user: null,
authenticationError: null,
isLoggingIn: false,
isLoggingOut: false
});
})
.then(() => {
navigate('/', { replace: true });
});
However, if I then refresh the page then this thinks that I am still logged in. (It is a multi-tenant system and the React app runs on a subdomain for each tenant.)
useEffect(() => {
const doEffect = async () => {
let s: string = appSettings?.rootTenantSubdomain ?? 'prestwood';
let isAuthenticatedResult: boolean = false;
try {
s = getFirm();
isAuthenticatedResult = await isAuthenticated();
} catch {
return;
}
// If the browser is on a subdomain other than that in the token the redirect
// because we believe the token more than we believe the browser.
if (
isAuthenticatedResult &&
s !== null &&
s !== undefined &&
s.toLowerCase() !== subdomain.toLowerCase() &&
state.user !== null &&
state.user.expired === false /*&& isAuthenticated()*/
) {
console.error(`Browser is at subdomain ${subdomain} but token firm is ${s} user: ${JSON.stringify(state.user)}`);
const newDomain = [...domain];
newDomain[0] = s;
window.location.replace(`${window.location.protocol}//${newDomain.join('.')}${window.location.pathname + window.location.search}`);
}
};
You will need to debug why, maybe a silent renew?
But I've logged out, revoked tokens, and cleared state -- it shouldn't have secretly retained a token.
And it all works fine both in a private window and in other browsers. Therefore I think that it's secretly keeping data that it shouldn't be.
session cookie?
I'm not using cookies. I'm using JWT.
This is still fucked.
I log out and on the callback do
const handleLogout = () => {
setAuthenticationState((currentState) => ({ ...currentState, isLoggingOut: true, user: null }));
console.log('handleLogout');
userManager.current
.removeUser()
.then(() => {
userManager.current.revokeTokens(); // Call the token revocation endpoint (when settings are set).
})
.then(() => {
userManager.current.clearStaleState();
})
.then(() => {
setAuthenticationState({
user: null,
authenticationError: null,
isLoggingIn: false,
isLoggingOut: false
});
})
.then(() => {
navigate('/', { replace: true });
});
}
and then at /
in useEffect
the fucking userManager.current.getUser
has reappeared.
Like @pamapa said it could be due to a silent renew.
You can clear/remove anything you wan't on the application side, but if you are not properly logged out from your IdentityServer (ie. if you still have a session running), then the next time you load your app, a silent renew can brings your tokens back.
So are you sure you are not doing a silent renew during your app launch ? And are you sure you are really logged out from your IdentityServer ?
I'm experiencing the same issue. Using oidc-client-ts with react-oidc-context. I've already set the automaticSilentRenew to false, logout with signoutRedirect(), clear the sessionStorage. But the web still got the authorization code params automatically on the browser which makes the user stays logged in.
go to your IDP, kick the user out and see if your application behaves correctly (nothing should works siginSilent or silent_Renew). As long as your IDP still "know" you're not logout via IDP it always bring your back (you have token).
This is what I'm doing at the moment:
const logOut = () => {
setAuthenticationState((currentState) => ({ ...currentState, isLoggingOut: true }));
if (!authenticationState.user) {
// Must be already logged out, or more likely oidc-client-ts is in a muddle.
userManager.current
.removeUser()
.then(() => {
userManager.current.revokeTokens(); // Call the token revocation endpoint (when settings are set).
})
.then(() => {
userManager.current.clearStaleState();
})
.then(() => {
setAuthenticationState({
user: null,
authenticationError: null,
isLoggingIn: false,
isLoggingOut: false
});
})
.then(() => {
navigate('/', { replace: true });
});
return;
}
const signoutRedirectArgs: SignoutRedirectArgs = {
extraQueryParams: undefined,
state: undefined,
post_logout_redirect_uri: `${window.location.protocol}//${window.location.host}/${serversideLogoutRedirectUrl}`,
id_token_hint: authenticationState.user!.id_token // https://github.com/IdentityServer/IdentityServer4/issues/1616
};
userManager.current.signoutRedirect(signoutRedirectArgs);
// State is removed in the callback.
};
and
...
} else if (isServersideLogoutRedirect()) {
setAuthenticationState((currentState) => ({ ...currentState, isLoggingOut: true, user: null }));
userManager.current
.removeUser()
.then(() => {
userManager.current.revokeTokens(); // Call the token revocation endpoint (when settings are set).
})
.then(() => {
userManager.current.clearStaleState();
})
.then(() => {
setAuthenticationState({
user: null,
authenticationError: null,
isLoggingIn: false,
isLoggingOut: false
});
})
.then(() => {
navigate('/', { replace: true });
});
} else {
...