Refresh and Logout
Token and session lifetimes
Section titled “Token and session lifetimes”Keycloak manages three related concepts that control how long a user stays logged in:
| Concept | Typical default | What it controls |
|---|---|---|
| Access token lifespan | 5 minutes | How long the JWT is valid before the backend rejects it |
| Refresh token lifespan | 30 minutes (SSO Session Idle) | How long a refresh token can be used to get new access tokens |
| SSO session max | 10 hours | Absolute maximum session length, even with active refresh |
When the access token expires, the frontend should use the refresh token to silently get a new one — without forcing the user to log in again. When the SSO session expires, the user must re-authenticate.
Refreshing tokens with updateToken
Section titled “Refreshing tokens with updateToken”keycloak.updateToken(minValidity) is the idiomatic way to handle refresh in keycloak-js. Call it before any API request; if the current access token will expire within minValidity seconds, keycloak-js silently exchanges the refresh token for a new access token:
// Refresh the token if it expires within 60 seconds,
// then call the API with the fresh token.
async function callApi(path) {
try {
await keycloak.updateToken(60);
} catch {
// Refresh token has expired — force re-login.
keycloak.login();
return;
}
const response = await fetch(`https://api.example.com${path}`, {
headers: { Authorization: `Bearer ${keycloak.token}` },
});
return response.json();
}If updateToken rejects (the refresh token is expired or revoked), the user’s session is gone and you should redirect them to login with keycloak.login().
Logging out properly
Section titled “Logging out properly”Calling a local “clear state” function in your app is not enough. The user’s SSO session still exists in Keycloak, which means they could immediately access other apps in the same realm without re-authenticating — or even return to your app and bypass the login screen.
A proper logout hits Keycloak’s end-session endpoint. keycloak-js does this for you:
// Redirect to Keycloak's end-session endpoint,
// then back to your app's home page.
keycloak.logout({ redirectUri: 'https://app.example.com/' });Under the hood this redirects the browser to:
/realms/{realm}/protocol/openid-connect/logout ?id_token_hint=<id_token> &post_logout_redirect_uri=https://app.example.com/Keycloak clears the SSO session cookie, marks the refresh token as revoked, and redirects back to your app.
What gets cleared
Section titled “What gets cleared”| Action | Clears local token | Clears Keycloak session |
|---|---|---|
| Local state reset only | Yes | No |
keycloak.logout() | Yes | Yes |
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
Silent refresh via updateToken() | The user is never interrupted; the session continues as long as the refresh token hasn’t expired | Requires complete error handling, because a silent refresh failure can leave the app looking logged in while every API call fails |
| Force a re-login immediately when the access token expires | Simpler to implement, no complex refresh flow to manage | Much worse UX — users must re-enter their password often, even though the SSO session itself hasn’t actually expired |
| Set a short SSO Session Idle/Max | Reduces the risk window if a token or session leaks | Users must authenticate again more often, hurting UX especially for apps used continuously for long periods |
Common mistakes
Section titled “Common mistakes”- Not handling the case where
updateToken()rejects — if the refresh token has expired or been revoked and the app doesn’t catch the error, the user keeps seeing failed API requests with no obvious cause. Always catch it and callkeycloak.login()to redirect back to authentication. - Logging out by only clearing local state, without calling the end-session endpoint — removing tokens from memory alone doesn’t clear Keycloak’s SSO session cookie, so the user is “logged out” of your app but still logged in realm-wide.
- Retrying refresh indefinitely on a transient network failure — not distinguishing a network error from a genuinely expired refresh token can make the app loop calling
updateToken()repeatedly without ever falling back to the login page.
Real-world example
The keycloak-js
updateTokenpattern — many production apps callupdateToken(minValidity)silently before every API call, exactly as this lesson shows, and catch the rejection to redirect to login only when the refresh token has genuinely expired, instead of letting requests fail silently.Google Workspace / Gmail on the web — uses the same idea: a long-lived session that refreshes automatically in the background, but with an absolute session timeout (similar to Keycloak’s SSO session max) that forces re-authentication periodically even while silent refresh keeps “succeeding.”