Keycloak’s token lifespan isn’t just about how long a user stays logged in; it’s a critical security and performance lever that dictates the frequency of token refreshes and the potential impact of a compromised token.

Let’s see this in action. Imagine a user logs into an application protected by Keycloak. They receive an access_token and a refresh_token. The access_token is used to access protected resources. Its lifespan is relatively short, say 5 minutes.

{
  "iss": "http://localhost:8080/auth/realms/myrealm",
  "sub": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "aud": "my-client-app",
  "exp": 1678886400, // Unix timestamp for expiry
  "iat": 1678886100, // Unix timestamp for issued at
  "jti": "some-unique-id",
  "typ": "Bearer",
  "azp": "my-client-app",
  "scope": "openid profile email"
}

The exp field is the crucial part here. Once this timestamp passes, the access_token is invalid. The application will receive a 401 Unauthorized response when it tries to use this expired token.

To maintain the session without forcing the user to re-authenticate constantly, the refresh_token comes into play. This token has a much longer lifespan, perhaps 30 days. When the access_token expires, the application can use the refresh_token to obtain a new access_token from Keycloak’s token endpoint.

curl -X POST \
  http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=refresh_token&client_id=my-client-app&refresh_token=eyJhbGciOiJkaXIiLCJlbmj...&scope=openid%20profile%20email'

This mechanism allows for a balance: short-lived access tokens limit the damage if a token is intercepted, while long-lived refresh tokens provide a seamless user experience.

The core problem Keycloak’s token lifespan configuration solves is managing the trade-off between security and usability in stateless authentication. In traditional session-based authentication, a server maintains a session state for each logged-in user. This is stateful. With JWTs (like Keycloak’s access tokens), the token itself contains the necessary information, making the authentication stateless. However, a long-lived, unrevocable JWT is a security risk. Keycloak’s token lifespan settings allow you to define how frequently these tokens need to be refreshed or re-issued, effectively managing the "session" without explicit server-side state.

Internally, Keycloak generates these JWTs with claims like exp (expiration time) and iat (issued at time). When a client presents an access token, Keycloak (or the resource server it trusts) validates these claims. The exp claim is paramount; if the current time is past exp, the token is rejected. The refresh_token is a separate entity, often a random string, that Keycloak uses to issue new access tokens. Keycloak tracks the lifespan of these refresh tokens server-side.

You control these lifespans primarily through the Keycloak Admin Console. Navigate to your realm, then to Tokens under the General settings. Here you’ll find:

  • Access Token Lifespan: This is the exp claim on the access_token. For example, setting this to 600 seconds means the access_token is valid for 10 minutes.
  • Access Token Lifespan For Client: This allows overriding the realm-wide access token lifespan for specific clients. You might set this to 300 seconds for a mobile app where tokens are more frequently exchanged.
  • Client Session Idle Timeout: This is the maximum time a client session can remain idle before Keycloak invalidates the session and any associated refresh tokens. Setting this to 1800 seconds (30 minutes) means if a user hasn’t interacted with any protected application for 30 minutes, their session is considered dead, and they’ll need to log in again.
  • Client Session Max Lifespan: This is the absolute maximum duration a client session can exist, regardless of activity. Setting this to 7200 seconds (2 hours) means even if the user is constantly active, their session will expire after 2 hours, requiring a full re-authentication.
  • Refresh Token Lifespan: This defines how long a refresh_token is valid. A value of 2592000 seconds (30 days) means a user can continue to get new access tokens using their refresh token for up to 30 days after their initial login, provided their client session hasn’t expired or been maxed out.
  • Refresh Token Max Lifespan: Similar to Client Session Max Lifespan, this sets an absolute maximum for the refresh token’s validity.

The Client Session Idle Timeout and Client Session Max Lifespan work in tandem to manage the user’s overall "session" as perceived by Keycloak. The Refresh Token Lifespan and Refresh Token Max Lifespan govern the longevity of the token used to obtain new access tokens. It’s crucial to understand that the access_token lifespan is independent of the client session and refresh_token lifespans; it’s purely about how long the JWT itself is considered valid.

Many administrators overlook the Client Session Max Lifespan and Refresh Token Max Lifespan settings, leaving them at their default (often infinite or a very large number). However, for robust security, especially in environments where devices might be lost or compromised, it’s vital to set these to a reasonable finite duration. This ensures that even if a refresh token is stolen, it cannot be used indefinitely to re-authenticate. The truly surprising part is how these two settings (session max lifespan and refresh token max lifespan) interact: if either one expires, the user is effectively logged out and will need to re-authenticate fully.

The next logical step after mastering token lifespans is understanding how to implement token revocation, which provides an immediate way to invalidate tokens before their natural expiry.

Want structured learning?

Take the full Keycloak course →