Skip to content

tut: Keycloak session and token timeouts, explained - #376

Merged
xgp merged 3 commits into
mainfrom
content/T67-session-token-timeouts
Sep 14, 2026
Merged

xgp merged 3 commits into
mainfrom
content/T67-session-token-timeouts

Conversation

@xgp

@xgp xgp commented Sep 7, 2026

Copy link
Copy Markdown
Member

Keycloak Session and Token Timeouts, Explained

Queue item: T67 · Type: tutorial · Track: Sessions and tokens (new)
Publish target: week of 2026-09-14
Path: tutorials/sessions/timeouts.mdx/tutorials/sessions/timeouts/
Primary keyword: keycloak session timeout
Secondary: keycloak token lifespan, keycloak sso session idle, keycloak access token lifespan, keycloak refresh token expiration

What this helps a reader do

Configure Keycloak's twelve interacting session and token timeouts deliberately instead of
by trial and error, and know which setting actually bounds each risk.

The official Session and token timeouts
reference is a good definition list and this page links to it rather than restating it. What
it does not give you is which setting wins when two disagree, what the defaults are, what the
REST field behind each console label is called, or what breaks. This page adds:

  • A label → REST field → default mapping for all 20 settings across the Sessions and
    Tokens tabs, plus the five client-level override attribute keys and the four per-action
    realm attributes. These are needed for kcadm.sh, Terraform and realm JSON, and the
    mapping is not published anywhere. Read out of the admin console shipped in 26.7.3.
  • A measured interaction matrix — seven realm configurations, with the token endpoint's
    own expires_in / refresh_expires_in for each — and five precedence rules derived from it.
  • A decision table of six deployment profiles with starting values and the reasoning.
  • Named failure modes with the exact error strings Keycloak returns.

The three findings that make this worth publishing

  1. An access token outlives its own session. With SSO Session Idle at 60s and Access
    Token Lifespan at 300s, at t+91s the refresh grant returns invalid_grant, /userinfo
    returns 401 and introspection says active: false — but the JWT still verifies against
    the realm JWKS with 200+ seconds left. Any resource server doing local signature
    validation (the recommended default) accepts it. So session idle bounds
    re-authentication; only Access Token Lifespan bounds the token. Stated plainly, including
    the cost of the default.
  2. The documented "two-minute idle grace window" does not apply to the refresh grant.
    The docs qualify it with "only if persistent user sessions are not active", and persistent
    user sessions have been on by default since Keycloak 26. Measured both ways on 26.7.3 —
    five independent sessions per run, one probe each, since a successful refresh resets the
    idle clock — and the results are identical: expiry is exact at the configured idle in both
    modes. A lot of third-party advice still says to budget the extra two minutes.
  3. refresh_expires_in shrinks as a session ages (measured 150 → 139 → 79 as the
    remaining max lifespan falls below the idle timeout). Clients that cache the first value
    schedule their last refresh after the session has already ended.

Verified against

  • Keycloak 26.7.3 (quay.io/keycloak/keycloak:26.7.3, start-dev). Every default,
    number and error string in the page is copied from an actual run; nothing is from memory.
  • A second container started with --features-disabled=persistent-user-sessions for the A/B
    in finding 2.
  • Console label → REST field names and the per-action attribute keys were read out of the
    admin console bundle in that release rather than inferred.
  • Keycloak docs consulted and linked: Session and token timeouts, Offline access,
    Configuring distributed caches, and the 26.0 release notes for the persistent-user-sessions
    default.

Could not confirm

  • Browser SSO re-authentication via the session cookie is a different code path from the
    refresh grant and may still use the two-minute window. Only the refresh grant was measured;
    the page says so explicitly and does not claim the window is gone everywhere.
  • The decision table values are recommendations, not measurements, and are framed that
    way in the text.

Editorial notes

  • No authors: frontmatter — no tutorial in this section carries one and the tutorials
    plugin does not render a byline. Flagging rather than introducing an unused field.
  • <ProductionNote /> is the only Phase Two mention, which is also where the canonical
    commercial link lives. Nothing in the tutorial requires our product.
  • Adds a Sessions and tokens category to sidebars.tutorials.js (first tutorial in the
    track) and one line to the tutorials index learning path.

Internal links

  • Get a Keycloak token and read every claim → /tutorials/getting-started/your-first-token/
  • Run Keycloak locally → /tutorials/getting-started/run-keycloak-locally/
  • JWT security best practices → /tutorials/jwts/jwt-security-best-practices/
  • Benefits and drawbacks of JWTs → /tutorials/jwts/jwt-benefits-drawbacks/
  • Enterprise SSO → /docs/authentication/sso
  • Managed Keycloak hosting → /hosting/dedicated-clusters/ (via <ProductionNote />)

Follow-ups, once their pages are on main: this page wants links to the offline-access,
session-limits and OIDC-logout tutorials in the same track. They are in separate PRs and do
not exist on this branch, so the link checker would reject them — deliberately left out.

Checklist

  • pnpm install --frozen-lockfile && pnpm build passes
  • Keyword in title, description and first 150 words
  • One extractable direct-answer block (the two rules, up top)
  • ≥1 canonical commercial link, ≥2 sibling links, ≥1 docs link
  • Every code block and every number tested against 26.7.3
  • keycloak_version frontmatter set
  • <ProductionNote /> present and is the only Phase Two mention
  • No hero image (none produced — no image: key)

Rationale for the item and its place in the plan is in the private content-marketing repo.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 7, 2026

Copy link
Copy Markdown

Deploying phasetwo-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 22700f7
Status: ✅  Deploy successful!
Preview URL: https://dd1917fb.phasetwo-docs.pages.dev
Branch Preview URL: https://content-t67-session-token-ti.phasetwo-docs.pages.dev

View logs

@xgp
xgp marked this pull request as ready for review September 7, 2026 10:29
xgp added 2 commits September 14, 2026 10:11
Both sides added a new sidebar category in the same position: this branch's "Sessions and
tokens", and "Securing applications" which landed on main in #372 and #373 while this sat
open. Kept both.

"Sessions and tokens" goes after "JSON Web Tokens (JWT)" rather than where either side had
it. That is where tutorials/index.md already puts it -- the timeouts tutorial is step 5 of
the "Working with tokens" learning path, after the three JWT ones -- and it leaves main's
existing category order untouched.

tutorials/index.md merged cleanly and reads correctly: the new "Securing an application"
path sits above the token path, and its "More framework-by-framework guides are next"
line is still true.
Every URL on this site is served and canonicalised with a trailing slash, and this was the only /docs/authentication/sso without one anywhere in the repo. Not broken -- it redirects -- but a redirect hop on a page about to publish, and inconsistent with the four other internal links in the same file.
@xgp
xgp merged commit 9977e5f into main Sep 14, 2026
3 checks passed
@xgp
xgp deleted the content/T67-session-token-timeouts branch September 14, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants