Skip to content

fix(keycloak): raise dev reset-credentials token lifespan to 30m (WS-05) - #276

Merged
TechGardenCode merged 1 commit into
mainfrom
fix/ws-05-reset-credentials-lifespan
Aug 5, 2026
Merged

fix(keycloak): raise dev reset-credentials token lifespan to 30m (WS-05)#276
TechGardenCode merged 1 commit into
mainfrom
fix/ws-05-reset-credentials-lifespan

Conversation

@TechGardenCode

Copy link
Copy Markdown
Owner

Follow-up to #275, raised by the WS-05 orchestrator during stage 3 joint validation.

The bug

Keycloak resolves the reset-credentials action token from the base actionTokenGeneratedByUserLifespan. #275 pinned that at 300 and overrode only verify-email, so forgot-password links in dev expire in 5 minutes — on the exact flow WS-04 was built to provide.

The fix

"actionTokenGeneratedByUserLifespan.reset-credentials": "1800"

30 minutes. Per-action override rather than raising the base, so verify-email keeps its 12h and any future user-initiated action still inherits Keycloak's conservative 300s unless deliberately overridden.

Why 300 was wrong

It was a deliberate choice in #275 — but reasoned against 43200 as the only alternative, on the grounds that a 144× wider credential-reset window buys nothing. That's true and irrelevant: a middle value was never considered. 1800 is 6×, sits in the normal band for password-reset tokens, and makes the flow usable.

Scope

Realm-only. Reconciled by the existing keycloak-config-cli PostSync hook via the Admin API — no theme bytes touched, so no theme-revision bump and no pod roll.

Resulting dev lifespans:

Flow Resolves from Value
admin execute-actions-email (invite) actionTokenGeneratedByAdminLifespan 259200 (72h)
verify-email attribute override 43200 (12h)
forgot-password attribute override 1800 (30m)
any other user-initiated action base 300 (5m)

Validation

  • python3 -m json.tool on the realm seed — valid
  • kustomize build kubernetes/clusters/1276-dev/keycloak/keycloak — pass

🤖 Generated with Claude Code

https://claude.ai/code/session_01S5ph2xAnD7oCR8YmFmobDn

Forgot-password links in the dev techgarden realm expired in 5 minutes.
Keycloak resolves the reset-credentials token from the base
actionTokenGeneratedByUserLifespan, which #275 pinned at 300 — so the
verify-email override landed but the reset flow kept the default.

That 300 was a decision, but a badly framed one: it was chosen against
43200 as the only alternative, on the grounds that a 144x wider window
for credential reset buys nothing. A middle value was never considered.
1800 is 6x, sits in the normal band for password-reset tokens, and makes
the flow WS-04 exists to provide actually usable — request a reset, go
find your phone, open the mail six minutes later, and the link still
works.

Per-action override rather than raising the base, so verify-email keeps
12h and any future user-initiated action still inherits Keycloak's
conservative 300s unless deliberately overridden.

Realm-only change: reconciled by the config-cli PostSync hook via the
Admin API. No theme bytes touched, so no theme-revision bump and no pod
roll needed.

Reported by the WS-05 orchestrator during stage 3 joint validation.

Refs: WS-05, TechGardenCode/techgarden#181, #275

Claude-Session: https://claude.ai/code/session_01S5ph2xAnD7oCR8YmFmobDn
@TechGardenCode
TechGardenCode merged commit 3464aba into main Aug 5, 2026
6 checks passed
@TechGardenCode
TechGardenCode deleted the fix/ws-05-reset-credentials-lifespan branch August 5, 2026 01:11
TechGardenCode added a commit that referenced this pull request Aug 8, 2026
…WS-02 H3) (#280)

Adds everything the prod techgarden realm needs EXCEPT the one line that turns it
on. This is the only change in WS-02 touching a live shared IdP, so it is isolated:
a broken hausparty or kian-coffee login is attributable to this PR instantly rather
than bisected out of a large merge.

THE GO SWITCH: base/realms/techgarden-realm.json exists but is deliberately absent
from configMapGenerator.files. config-cli imports /config/*.json from that
ConfigMap, so an unlisted file is never seen by Keycloak and
https://sso.techgarden.gg/realms/techgarden keeps returning 404 — the pass
condition for this phase, not a failure. The flip is that one line.

Realm — DERIVED from the dev seed, not copied. Verified deltas vs dev, and nothing
else drifted:
  1. apex hostnames only — https://techgarden.gg/* and /oauth2/callback (ADR-0006:
     products are routes, not subdomains). No dev.techgarden.gg anywhere.
  2. fromDisplayName "TechGarden", not "TechGarden (dev)" — a verbatim copy would
     put the wrong sender name on every production email.
  3. registrationAllowed: false, declared not defaulted (ADR-0052).
  4. all FOUR action-token lifespans carried (reset-credentials 1800, verify-email
     43200, admin 259200, base 300). The base value alone would expire
     forgot-password links in 5 minutes — the bug dev shipped and fixed in #276.
  5. THE FOUR DEV PERSONAS DROPPED. dev/power/casual/fresh are a dev fixture with
     out-of-band passwords; this IdP also fronts hausparty and kian.coffee. Prod
     gets the owner only.
Also carried from WS-03: confidential client techgarden-gateway,
revokeRefreshToken: true, 30-day idle / 60-day cap. And the `ai` realm role from
#278, which landed after the brief was written (owner-only, held by kian).

Theme — 17 files (11 login, 6 email), byte-identical to dev, mounted via
spec.unsupported.podTemplate at /opt/keycloak/themes/techgarden/. TWO ConfigMaps,
not one: configMapGenerator keys off each file's base name and ConfigMap keys
cannot contain "/", so theme.properties and messages_en.properties collide across
login/ and email/. theme-revision starts at "1" — prod's counter is independent of
dev's "2" and the two must never be synced up. Nothing references the theme until
the realm is enabled.

Substitution wiring — the sharpest edge. IMPORT_VARSUBSTITUTION_ENABLED is true
over /config/*.json, so a seed referencing an unwired variable fails substitution
for EVERY realm file in the batch at once. KC_CLIENT_TECHGARDEN_GATEWAY_SECRET and
KC_SMTP_PASSWORD are therefore wired NOW, alongside the two new ExternalSecret
keys, so the flip cannot take hausparty and kian-coffee down with it.

Resend: prod SHARES the dev sender. The free tier allows one verified domain and
there is exactly one `resend` entry in the BWS org — so both environments share the
3,000/month cap and ADR-0052's fail-closed-on-429 becomes a shared property.

Claude-Session: https://claude.ai/code/session_015tcbrNifvkc8ryk4g2M7XK
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.

1 participant