[BUG] Cookie SSR auth loops infinitely — session cookie value (4719B) exceeds browser per-cookie limit #24
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Bug
Lineage
Discovered during post-merge end-to-end validation of
forgejo_admin/westside-admin#2's 4-way decomposition (PRs #18 / #20 / #21 / #23, all merged 2026-05-03). Regression from the original ACs of#16(/auth/callbacksets the session cookie) and#15(hook reads it on the next request) — both PRs implemented the spec correctly per static review, but the runtime cookie value exceeds the browser per-cookie size limit, so the loop never terminates.Repo
forgejo_admin/westside-adminWhat Broke
The full SSO round-trip for an admin user produces an infinite
westside-admin/↔/auth/login↔ Keycloak ↔/auth/callbackredirect loop, ending inchrome-error://chromewebdata/ ERR_TOO_MANY_REDIRECTSafter Chromium's redirect cap (~20 hops).The session cookie that
/auth/callbackmints is 4719 bytes (URL-safe base64 of AES-GCM-encrypted{access_token, refresh_token, id_token, exp, refresh_exp}). RFC 6265 §6.1 mandates a 4096-byte per-cookie minimum and most browsers (including Chromium) cap there. Result: the browser silently drops theSet-Cookie: westside_admin_session=...header on the callback's 302 response. The next request to/arrives with no session cookie, the hook redirects back to/auth/login, Keycloak SSO-skips the realm session and returns a fresh code, callback sets a still-too-big cookie, browser drops it again, infinite loop.Repro Steps
adminrole athttps://westside-admin.tail5b443a.ts.net.ERR_TOO_MANY_REDIRECTS.Set-Cookiefrom CDP-derived response-headers display, so it must be done outside Playwright):len(cookie_value)→ 4719 bytes → over RFC 6265 §6.1 limit.Reproducible 100% — every realm user with a typical Keycloak token set hits the same ceiling.
Expected Behavior
Per
#15AC: "Request with valid session cookie + admin role passes through, populatesevent.locals.user." That requires the browser to actually retain the cookie set on the previous response. The cookie value must therefore stay under 4096 bytes.Environment
westside-adminnamespace,archboxk3s50731870747636a4ed9e0ea9daa6cc9706342cf5(matches ForgejomainHEAD post-#23 merge)westside-admin-575d5d55bf-rfs6z(1/1 Running)westside-basketballrealm):access_token: 801 Brefresh_token: 668 Bid_token: 1118 BProposed Fix
Drop
id_tokenfrom the session payload insrc/routes/auth/callback/+server.tsandsrc/lib/server/keycloak.ts'sKeycloakTokens/refresh path.id_tokenis currently consumed only by/auth/logoutto populateid_token_hinton the Keycloak/logoutredirect —id_token_hintis optional per OIDC spec; without it Keycloak still performs realm-session logout, just without per-client SLO targeting. Acceptable trade-off forwestside-adminv1.After dropping
id_token:access_token(801) +refresh_token(668) + 2 ints + JSON wrap → ≈ 1700 B plaintextThe frozen-lib constraint that forced the original design no longer applies —
#22was already opened today to extendKeycloakTokenswithrefresh_exp; this fix can ride the same migration window.Acceptance Criteria
westside_admin_sessioncookie is < 4096 bytes (verified via the Python repro in Repro Steps)./carries it; hook validates it and resolves the request./withevent.locals.userpopulated./logout);id_token_hintparameter may be omitted./auth/callbackfailure paths (state mismatch → 400, Keycloak token failure → 502, etc.).#22'srefresh_expplumbing not regressed — the field stays in the payload.Related
project-westside-adminforgejo_admin/westside-admin#2— original parent (closed but the regression is in its consumers)forgejo_admin/westside-admin#15— hook (consumes the cookie)forgejo_admin/westside-admin#16— callback (mints the cookie)forgejo_admin/westside-admin#22— open follow-up that already touches the same payload (consider bundling, but perfeedback_smaller_scopes_parallelkeep them separate)feedback_validate_before_done— this validation gate is what caught the bugfeedback_funnel_requires_auth— without this fix, the funnel-auth gate is non-functionalScope Review: APPROVED
Review note:
review-1140-2026-05-03Bug template fully populated with first-rate forensics (live-measured token sizes, RFC 6265 §6.1 citation, cluster image SHA
50731870747636a4ed9e0ea9daa6cc9706342cf5, exact failure topology). File targets verified at HEADb222400. Proposed fix is correct (id_token_hintis OPTIONAL per OIDC spec) and the math checks out (4719 B → ~2300 B after droppingid_token).Two
[BODY]notes for the dev agent (not blocking, but worth recording before in_progress):Logout shape-check relaxation required.
isSessionBlobinsrc/routes/auth/logout/+server.tsline 42 currently requiresid_token === null || typeof id_token === 'string'. After droppingid_tokenfrom the cookie payload, this shape-check will reject every new session as malformed. Relax it (or drop theid_token_hintbranch entirely) in the same PR. AC4 ("Logout still works") will catch this if missed — but flagging here saves a re-review iteration.Coordinate with
#22(open, untouched). Both tickets editsrc/lib/server/keycloak.tsandsrc/hooks.server.ts. Files overlap but interface/field changes do NOT collide (#22 addsrefresh_exptoKeycloakTokens; #24 changes the cookie payload shape in callback). Whichever lands first, the second rebases. No semantic conflict.Traceability:
story:admin-row-crudverified —story-westside-admin-admin-row-crudexists in project page User Stories sectionarch:westside-adminverified — satisfied by the three project-specific arch notes (arch-domain-,arch-dataflow-,arch-deployment-westside-admin)arch:keycloak— backing notearch-keycloakMISSING. Known platform gap (flagged in 9+ prior reviews). Treat as WAIVER per established precedent — NOT blocking this ticket.Decomposition: Not needed. 2 files modified, 7 testable AC, single repo. Single dev agent, single PR.
Cleared for
todo. Hook will accept theAPPROVEDverdict.