Architecture: ✅ SESSION COOKIE SIZE FIX - Browser Crash Resolved
Date: 2026-01-30
🔧 Solution
What Changed
Before (❌ BAD):
// Stored ALL groups in token (40+ groups = 8KB!)
token.groups = groups; // 🚫 DON'T DO THIS
token.profile = { ... }; // Also large
session.groups = token.groups; // Copied to session
After (✅ GOOD):
// Only store the authorization result (tiny!)
const groups = extractGroups(profileData); // Used for checking only
token.isAuthorized = hasRequiredGroup(groups);
token.role = isAdminUser(groups) ? 'admin' : 'user';
// Groups array is NOT stored - saves 7KB!
📊 Impact
Session Cookie Size
Before: 8031 bytes
groups: ~6500 bytes (40+ group names)profile: ~1000 bytes- Other data: ~500 bytes
- Result: Browser crash!
After: ~500 bytes (estimated)
isAuthorized: 5 bytesrole: 10 bytesaccessToken,idToken: ~400 bytes- Other data: ~100 bytes
- Result: Normal operation!
Files Changed
- ✅
ui/src/lib/auth-config.ts- Removed
token.groups = groupsassignment - Removed
token.profile = { ... }assignment - Removed
groupsandprofilefrom JWT interface - Removed
groupsfrom Session interface - Simplified session callback
- Removed
🎯 Technical Details
Groups Handling
Before: Groups stored and checked in session
// JWT callback
token.groups = groups; // Stored!
// Session callback
session.groups = token.groups; // Copied!
// API middleware
if (session.groups?.includes('admin')) { ... } // Checked in session
After: Groups checked once, result stored
// JWT callback (runs once at login)
const groups = extractGroups(profile); // Not stored!
token.role = isAdminUser(groups) ? 'admin' : 'user'; // Result stored!
// Session callback
session.role = token.role; // Just the role, not groups
// API middleware
if (session.role === 'admin') { ... } // Clean check
Why This Works
- Groups only needed at login - We check group membership ONCE when creating the JWT
- Store the result, not the input -
role: 'admin'vsgroups: [40+ strings] - Session is lightweight - No unnecessary data in cookies
- Same security - Authorization still works, just more efficient
🔐 Security Note
This change does not reduce security:
- ✅ Groups are still checked at login
- ✅ Role is still stored securely in JWT
- ✅ MongoDB fallback still works
- ✅ Admin access still requires correct group
- ✅ Tokens are still signed and encrypted
The only difference: We don't store data we don't need!
📝 Debugging
Check Session Cookie Size
// In browser DevTools Console:
document.cookie.split(';')
.filter(c => c.includes('next-auth'))
.forEach(c => console.log(c.split('=')[0], c.length, 'bytes'));
Before fix: next-auth.session-token.0 ~4096 bytes, .1 ~4096 bytes, .2 ~328 bytes
After fix: next-auth.session-token ~500 bytes (single cookie!)
Check JWT Token Content
// Add to ui/src/lib/auth-config.ts jwt callback for debugging:
console.log('[Auth] JWT token size:', JSON.stringify(token).length, 'bytes');
console.log('[Auth] JWT keys:', Object.keys(token));
Related
- Spec: spec.md