Problem statement
When using OIDC authentication with Keycloak (or other IdPs that include large claims in the ID token), the session cookie can exceed the 4KB browser cookie size limit. This causes the browser to silently reject the cookie, resulting in authentication failure after the OIDC callback redirect. The user successfully logs in but then sees 401 Unauthorized errors because the session cookie is not stored by the browser.
Example from production:
- Keycloak returns ID tokens with
sid, session_state, and other claims
- Base64-encoded session payload exceeds 4KB
- Browser rejects the
radar_session cookie
- All subsequent API requests return 401
Proposed solution
Add automatic cookie chunking support that transparently splits large session cookies into multiple smaller cookies when the payload exceeds the safe limit (3800 bytes, leaving headroom for cookie attributes).
Implementation approach:
-
Cookie creation: When the cookie value exceeds 3800 bytes:
- If ID token is present, drop it and retry (ID token is only needed for RP-Initiated Logout and can be omitted)
- If still too large, split the value into chunks of ~3700 bytes each
- Create chunk cookies named
radar_session_chunk_0, radar_session_chunk_1, etc.
- Create a meta-cookie
radar_session_chunks containing the chunk count
-
Cookie parsing:
- Check for the main cookie first (for backward compatibility)
- If not present, look for
_chunks meta-cookie
- Reassemble chunks in order
- Verify HMAC signature on the reassembled value
-
Secure flag handling:
- Set
Secure flag based on X-Forwarded-Proto header
- Use
__Secure- prefix for secure cookies
- Apply to both main cookie and chunk cookies
-
Fallback behavior:
- Attempt to drop ID token before chunking (most tokens still fit without ID token)
- Log warnings when chunking is necessary
- Last resort: truncate the cookie (with warning) for extremely large cases
Alternatives considered
-
Server-side session storage with cookie ID only
- Store session data on server, use random ID in cookie
- Rejected because: Requires shared session storage (Redis/DB) which adds operational complexity for single-replica deployments
-
Compress cookie value before storing
- Use gzip/zstd compression on payload
- Rejected because: Base64 + compression is unpredictable, may not reduce size enough
-
Use localStorage + JWT instead of cookies
- Store session token in localStorage, send in Authorization header
- Rejected because: Requires significant frontend changes, less secure (XSS vulnerability)
-
Reduce claims in ID token
- Configure Keycloak to exclude large claims
- Rejected because: Not under our control; IdP configuration varies per deployment
-
Split session into multiple independent cookies
- Store username in one cookie, groups in another, etc.
- Rejected because: Complex to manage, increases signature overhead
Additional context
Browser cookie limits:
- Chrome: 4096 bytes per cookie (RFC 6265 requires browsers to support at least 4096)
- Firefox: 4097 bytes
- Safari: 4096 bytes
- We use 3800 bytes as safe limit to leave room for cookie name and attributes
Current session cookie structure:
radar_session=eyJ1IjoiYWxpY2UiLCJnIjpbImRldnMiXSwiZSI6MTc0N...base64.HMAC-signature
text
Chunked cookie example:
radar_session_chunks=3
radar_session_chunk_0=eyJ1IjoiYWxpY2UiLCJnIjpbImRldnMiXSwiZSI6MTc0NTI...
radar_session_chunk_1=...continuation
radar_session_chunk_2=...continuation
text
Impacted files:
pkg/auth/cookie.go - main cookie implementation
pkg/auth/auth.go - exports cookie functions
internal/auth/middleware.go - authenticates requests
internal/auth/oidc.go - sets cookie after OIDC login
Testing done:
- Unit tests for chunking logic
- Manual testing with Keycloak
- Verified cookie size with browser dev tools
pull request #497
Problem statement
When using OIDC authentication with Keycloak (or other IdPs that include large claims in the ID token), the session cookie can exceed the 4KB browser cookie size limit. This causes the browser to silently reject the cookie, resulting in authentication failure after the OIDC callback redirect. The user successfully logs in but then sees 401 Unauthorized errors because the session cookie is not stored by the browser.
Example from production:
sid,session_state, and other claimsradar_sessioncookieProposed solution
Add automatic cookie chunking support that transparently splits large session cookies into multiple smaller cookies when the payload exceeds the safe limit (3800 bytes, leaving headroom for cookie attributes).
Implementation approach:
Cookie creation: When the cookie value exceeds 3800 bytes:
radar_session_chunk_0,radar_session_chunk_1, etc.radar_session_chunkscontaining the chunk countCookie parsing:
_chunksmeta-cookieSecure flag handling:
Secureflag based onX-Forwarded-Protoheader__Secure-prefix for secure cookiesFallback behavior:
Alternatives considered
Server-side session storage with cookie ID only
Compress cookie value before storing
Use
localStorage+ JWT instead of cookiesReduce claims in ID token
Split session into multiple independent cookies
Additional context
Browser cookie limits:
Current session cookie structure:
radar_session=eyJ1IjoiYWxpY2UiLCJnIjpbImRldnMiXSwiZSI6MTc0N...base64.HMAC-signature
text
Chunked cookie example:
radar_session_chunks=3
radar_session_chunk_0=eyJ1IjoiYWxpY2UiLCJnIjpbImRldnMiXSwiZSI6MTc0NTI...
radar_session_chunk_1=...continuation
radar_session_chunk_2=...continuation
text
Impacted files:
pkg/auth/cookie.go- main cookie implementationpkg/auth/auth.go- exports cookie functionsinternal/auth/middleware.go- authenticates requestsinternal/auth/oidc.go- sets cookie after OIDC loginTesting done:
pull request #497