12 KiB
🔍 Authentication System Audit Report
Random User Logout Issues - Complete Analysis
Date: December 15, 2025
Status: ⚠️ CRITICAL ISSUES FOUND
Priority: HIGH
📋 Executive Summary
This audit identified 8 CRITICAL issues and 5 moderate issues that could cause random user logouts. The system has multiple aggressive logout triggers that were likely implemented to prevent session contamination, but these are now causing false positives and logging out legitimate users.
🔴 CRITICAL ISSUES (Immediate Action Required)
1. Aggressive Session Integrity Checks in Middleware
Location: backend/igny8_core/auth/middleware.py (Lines 55-82)
Problem:
The AccountContextMiddleware validates _account_id and _user_id stored in session on EVERY request. If there's ANY mismatch, it immediately logs out the user.
# Session contamination detected - force logout
if stored_account_id and stored_account_id != request.account.id:
logout(request)
return JsonResponse({'error': 'Session integrity violation...'})
Why This Causes Random Logouts:
- Race conditions during account switching
- Database updates to account relationships
- Session data not yet synchronized
- Multiple tabs/windows with different accounts
- Session persistence delays
Impact: HIGH - Affects all authenticated users on every request
2. JWT Token Expiry Too Short
Location: backend/igny8_core/settings.py (Line 523)
Problem:
JWT_ACCESS_TOKEN_EXPIRY = timedelta(minutes=15) # Too short!
Why This Causes Random Logouts:
- Users idle for >15 minutes get logged out
- Token refresh mechanism has race conditions
- Frontend proactive refresh (12 minutes) doesn't always succeed
- Network delays can cause refresh to happen after expiry
Impact: HIGH - Affects users during long operations or idle periods
3. Session Cookie Age = 24 Hours but SESSION_SAVE_EVERY_REQUEST = False
Location: backend/igny8_core/settings.py (Lines 100-101)
Problem:
SESSION_COOKIE_AGE = 86400 # 24 hours
SESSION_SAVE_EVERY_REQUEST = False # Session not extended on activity
Why This Causes Random Logouts:
- Session expires exactly 24 hours after login, even if user is active
- User working for >24 hours gets logged out mid-session
- No sliding window - fixed expiry time
Impact: MODERATE - Affects users with long sessions
4. Account/Plan Validation on Every Request
Location: backend/igny8_core/auth/middleware.py (Lines 181-195)
Problem:
Middleware calls validate_account_and_plan() on EVERY request, and if validation fails (account status changes, plan becomes inactive), user is IMMEDIATELY logged out.
validation_error = self._validate_account_and_plan(request, request.user)
if validation_error:
logout(request) # Immediate logout
return JsonResponse({...})
Why This Causes Random Logouts:
- Account status changes during active session (admin updates)
- Plan expiry/renewal processing
- Database replication lag
- Race conditions during billing operations
Impact: HIGH - Affects users when account/plan changes
5. Multiple Frontend Logout Triggers
Location: frontend/src/services/api.ts (Lines 194-200, 321-322, 327-328)
Problem: Frontend has multiple aggressive logout triggers:
// On 403 error:
if (errorMessage?.includes?.('Authentication credentials')) {
logout();
window.location.href = '/signin';
}
// On refresh token failure:
logout();
Why This Causes Random Logouts:
- 403 errors are triggered for permission issues (NOT just auth)
- Network timeouts interpreted as auth failures
- Plan/limit errors (402) causing logouts
- Race conditions during token refresh
Impact: HIGH - False positive logouts on permission/network errors
6. Proactive Token Refresh Race Condition
Location: frontend/src/layout/AppLayout.tsx (Lines 153-167)
Problem: Frontend proactively refreshes token every 12 minutes, but this can race with API calls:
const tokenRefreshInterval = setInterval(async () => {
await authState.refreshToken();
}, 720000); // 12 minutes
Why This Causes Random Logouts:
- Refresh fails → logout triggered
- Old token used during refresh window
- Multiple tabs triggering simultaneous refreshes
- Network delays causing refresh to fail
Impact: MODERATE - Periodic logout risk
7. Frontend Auto-Refresh User Data Every 2 Minutes
Location: frontend/src/layout/AppLayout.tsx (Lines 169, 91-180)
Problem:
Frontend calls refreshUser() every 2 minutes, on tab focus, and on visibility change. If ANY of these fail, it could trigger logout.
const intervalId = setInterval(() => refreshUserData(), 120000);
Why This Causes Random Logouts:
- API errors during refresh
- Network issues
- Backend temporary unavailability
- Race conditions with other API calls
Impact: MODERATE - Periodic logout risk
8. CSRF Token Issues (SameSite=Strict)
Location: backend/igny8_core/settings.py (Line 99)
Problem:
SESSION_COOKIE_SAMESITE = 'Strict' # Too restrictive
Why This Causes Random Logouts:
- Cookies not sent on cross-site navigation
- External redirects (OAuth, payment gateways) lose session
- Browser compatibility issues
- Subdomain navigation issues
Impact: MODERATE - Affects users with specific navigation patterns
⚠️ MODERATE ISSUES
9. No Session Backend Configuration
Location: backend/igny8_core/settings.py
Problem: No explicit session backend configured, defaults to database sessions.
Risk: Database connection issues → session loss → logout
10. JWT Refresh Token = 30 Days but No Rotation
Location: backend/igny8_core/settings.py (Line 524)
Problem: Long-lived refresh tokens without rotation increase security risk.
Risk: Stolen refresh token valid for 30 days
11. Multiple Authentication Methods Without Coordination
Location: backend/igny8_core/settings.py (Lines 251-254)
Problem: Three auth methods (API Key, JWT, Session) don't coordinate state.
Risk: Confusion about which method is authoritative, inconsistent logout behavior
12. Frontend Cookie Clearing is Aggressive
Location: frontend/src/store/authStore.ts (Lines 147-158)
Problem: Logout clears ALL cookies including domain variants.
Risk: Unintended side effects, potential conflicts with other services
13. No Graceful Degradation for Network Errors
Location: frontend/src/services/api.ts
Problem: Network timeouts treated same as auth errors.
Risk: Temporary network issues cause logout
🔧 ROOT CAUSE ANALYSIS
Primary Causes:
- Over-aggressive session validation - False positives
- Short token expiry + unreliable refresh - Race conditions
- Multiple logout triggers - No coordination
- No distinction between auth errors and other errors - False positive logouts
Secondary Causes:
- Fixed session expiry (no sliding window)
- SameSite=Strict blocking legitimate use cases
- Frequent auto-refresh increasing failure surface
💡 RECOMMENDED FIXES (Priority Order)
IMMEDIATE (Do First):
-
Remove session integrity checks from middleware
- Lines 55-82 in
backend/igny8_core/auth/middleware.py - Only validate on sensitive operations, not every request
- Lines 55-82 in
-
Increase JWT token expiry
- Change from 15 minutes to 60 minutes
JWT_ACCESS_TOKEN_EXPIRY = timedelta(hours=1)
-
Enable session sliding window
SESSION_SAVE_EVERY_REQUEST = True- Or increase to 7 days:
SESSION_COOKIE_AGE = 604800
-
Fix frontend 403 error handling
- Don't logout on permission errors
- Only logout on explicit "not authenticated" errors
- Check error message more carefully
-
Add retry logic for token refresh
- Retry 2-3 times before giving up
- Add exponential backoff
SHORT TERM (Next Sprint):
-
Change SameSite to Lax
SESSION_COOKIE_SAMESITE = 'Lax'
-
Reduce auto-refresh frequency
- Change from 2 minutes to 5-10 minutes
- Remove refresh on focus/visibility (keep only on mount)
-
Add error classification
- Distinguish network errors, permission errors, auth errors
- Only logout on auth errors
-
Add request deduplication
- Prevent multiple simultaneous token refreshes
LONG TERM (Future):
- Implement JWT token rotation
- Add session heartbeat endpoint
- Implement connection quality monitoring
- Add user session dashboard
🧪 TESTING RECOMMENDATIONS
-
Test session expiry scenarios
- Leave user idle for 15, 30, 60, 90 minutes
- Verify no unexpected logout
-
Test account changes during active session
- Admin updates account status
- Plan renewal/expiry
- Verify user not logged out
-
Test network failure scenarios
- Simulate network timeout
- Disconnect/reconnect
- Verify graceful recovery, no logout
-
Test multi-tab behavior
- Open multiple tabs
- Perform actions in parallel
- Verify no conflicts
-
Test token refresh under load
- Simulate concurrent API calls during refresh
- Verify no race conditions
📊 IMPACT ASSESSMENT
| Issue | Severity | Frequency | User Impact | Fix Complexity |
|---|---|---|---|---|
| Session integrity checks | HIGH | Every request | Very High | Low |
| JWT expiry too short | HIGH | Every 15min | High | Low |
| Account validation logout | HIGH | On changes | Medium | Medium |
| Frontend 403 logout | HIGH | On errors | High | Low |
| Token refresh race | MEDIUM | Every 12min | Medium | Medium |
| User auto-refresh | MEDIUM | Every 2min | Low | Low |
| SameSite Strict | MEDIUM | Specific flows | Medium | Low |
| Session expiry (24h) | LOW | After 24h | Low | Low |
🎯 SUCCESS CRITERIA
After implementing fixes:
- ✅ Users can work uninterrupted for 8+ hours
- ✅ Account/plan changes don't force logout
- ✅ Network errors don't cause logout
- ✅ Token refresh succeeds >99.9% of time
- ✅ Multi-tab usage works without issues
- ✅ Zero false-positive "session contamination" logouts
📝 CONCLUSION
The random logout issue is caused by multiple over-aggressive authentication checks that were likely added to prevent session contamination. While the intent was good, the implementation creates too many false positives.
The fix requires:
- Removing session integrity checks from hot path
- Increasing token expiry and adding retry logic
- Better error classification
- Enabling session sliding window
Estimated effort: 2-3 days for all critical fixes
Risk level: Low (mostly configuration changes)
Testing required: Moderate (need to verify all auth flows)
🔗 RELATED FILES
Backend:
backend/igny8_core/auth/middleware.py(Lines 1-207)backend/igny8_core/auth/utils.py(Lines 1-216)backend/igny8_core/auth/backends.py(Lines 1-36)backend/igny8_core/settings.py(Lines 93-108, 523-524)backend/igny8_core/api/authentication.py(Lines 1-172)backend/igny8_core/api/permissions.py(Lines 1-208)
Frontend:
frontend/src/store/authStore.ts(Lines 1-450)frontend/src/services/api.ts(Lines 1-2561)frontend/src/layout/AppLayout.tsx(Lines 1-300)
Report prepared by: GitHub Copilot
Audit methodology: Code review, flow analysis, error pattern analysis
Review status: ⏳ Awaiting stakeholder review