8.4 KiB
Inactivity Timeout and Logout Analysis
Issue 1: Dashboard Should Disconnect After 30 Minutes of Inactivity
Current State
Session Configuration (app/api/auth/options.ts:190):
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
}
SessionProvider Configuration (components/providers.tsx):
<SessionProvider>
{children}
</SessionProvider>
Problem Analysis
-
No Inactivity Detection:
- NextAuth session is set to 30 days maximum
- No client-side inactivity timeout logic exists
- No activity tracking (mouse movements, clicks, keyboard input)
- SessionProvider doesn't have
refetchIntervalconfigured
-
How NextAuth Sessions Work:
- NextAuth sessions are JWT-based (stateless)
- Session validity is checked on each request to
/api/auth/session - No automatic expiration based on inactivity
- Session expires only when
maxAgeis reached (30 days in your case)
-
What's Missing:
- Client-side activity monitoring
- Automatic session invalidation after inactivity period
- Session refresh based on activity (not just time)
Root Cause
NextAuth doesn't track user activity - it only tracks session age. The session will remain valid for 30 days regardless of whether the user is active or not.
Solution Requirements
To implement 30-minute inactivity timeout, you need:
-
Client-Side Activity Tracking:
- Monitor user activity (mouse, keyboard, clicks)
- Track last activity timestamp
- Store in
sessionStorageorlocalStorage
-
Session Invalidation Logic:
- Check inactivity period on each page interaction
- Call
signOut()if inactivity exceeds 30 minutes - Clear NextAuth session and Keycloak session
-
Activity Reset on User Actions:
- Reset inactivity timer on any user interaction
- Update last activity timestamp
-
SessionProvider Configuration:
- Optionally configure
refetchIntervalto check session periodically - But this won't help with inactivity - it only refreshes the session
- Optionally configure
Implementation Approach
The inactivity timeout must be implemented client-side because:
- NextAuth sessions are stateless (JWT)
- Server doesn't know about user activity
- Activity tracking requires browser events
Recommended Implementation:
- Create an
InactivityHandlercomponent - Monitor user activity events (mousemove, keydown, click, scroll)
- Store last activity time in
sessionStorage - Check inactivity every minute (or on page focus)
- If inactivity > 30 minutes, trigger logout
Issue 2: Applications Outside Dashboard Still Connected After Logout
Current Implementation
Logout Flow (components/main-nav.tsx, components/auth/signout-handler.tsx):
- Clear NextAuth cookies
- Clear Keycloak cookies (client-side attempt)
- Call
/api/auth/end-sso-session(NEW)- Uses Keycloak Admin API:
adminClient.users.logout({ id: userId })
- Uses Keycloak Admin API:
- Sign out from NextAuth
- Redirect to Keycloak logout endpoint with
id_token_hint
Problem Analysis
Why Applications Are Still Connected:
-
Keycloak Admin API
users.logout()Behavior:- The method
adminClient.users.logout({ id: userId })logs out the user from all client sessions - However, it may NOT clear the SSO session cookie (
KEYCLOAK_SESSION) - The SSO session cookie is what allows applications to auto-authenticate
- The method
-
SSO Session vs Client Sessions:
- Client Sessions: Per OAuth client (dashboard, app1, app2, etc.)
- SSO Session: Realm-wide, shared across all clients
users.logout()clears client sessions but may leave SSO session active- Applications check for SSO session cookie, not client sessions
-
Cookie Domain/Path Issues:
- Keycloak cookies are set on Keycloak's domain
- Client-side
clearKeycloakCookies()may not work if:- Cookies are
HttpOnly(can't be cleared from JavaScript) - Cookies are on different domain (cross-domain restrictions)
- Cookies have different path/domain settings
- Cookies are
-
Logout Endpoint Behavior:
- Keycloak logout endpoint (
/protocol/openid-connect/logout) withid_token_hint:- Clears the client session for that specific OAuth client
- May clear SSO session only if it's the last client session
- If other applications have active sessions, SSO session persists
- Keycloak logout endpoint (
Root Cause
The SSO session cookie persists because:
users.logout()Admin API method clears client sessions but may not clear SSO session cookie- Keycloak logout endpoint only clears SSO session if it's the last client session
- If other applications have active sessions, the SSO session remains valid
- Applications check for SSO session cookie, not client sessions
Why This Happens
Keycloak's SSO Design:
- SSO session is designed to persist across client logouts
- This allows users to stay logged in across multiple applications
- Logging out from one application shouldn't log out from all applications
- This is by design for SSO functionality
However, when you want global logout, you need to:
- Clear the SSO session cookie explicitly
- Or ensure all client sessions are logged out first
- Or use Keycloak's Single Logout (SLO) feature
Solution Requirements
To ensure applications are logged out:
-
Keycloak Configuration (Server-Side):
- Enable Front-Channel Logout for all clients
- Configure Back-Channel Logout URLs for each client
- This allows Keycloak to notify all applications when logout occurs
-
Admin API Limitations:
users.logout()may not clear SSO session cookie- Need to use Keycloak's logout endpoint with proper parameters
- Or use Keycloak Admin API to end SSO session directly (if available)
-
Alternative Approach:
- Use Keycloak's Single Logout (SLO) feature
- Configure all clients to participate in SLO
- When one client logs out, all clients are notified
What's Actually Happening
When you call /api/auth/end-sso-session:
- ✅ Admin API
users.logout()is called - ✅ All client sessions are logged out
- ❌ SSO session cookie may still exist
- ❌ Applications check SSO session cookie → still authenticated
When you redirect to Keycloak logout endpoint:
- ✅ Dashboard client session is cleared
- ✅ If it's the last client session, SSO session is cleared
- ❌ If other applications have active sessions, SSO session persists
- ❌ Applications can still authenticate using SSO session cookie
Verification Steps
To verify why applications are still connected:
-
Check if Admin API call succeeds:
- Look for console logs: "Successfully ended SSO session for user: {userId}"
- Check for errors in
/api/auth/end-sso-sessionendpoint
-
Check Keycloak session cookies:
- After logout, check browser cookies for:
KEYCLOAK_SESSIONKEYCLOAK_SESSION_LEGACYKEYCLOAK_IDENTITY
- If these cookies still exist, SSO session is still active
- After logout, check browser cookies for:
-
Check if other applications have active sessions:
- If other applications are open in other tabs/windows
- They may have active client sessions
- This prevents SSO session from being cleared
-
Check Keycloak Admin Console:
- Navigate to: Users → [User] → Sessions
- Check if sessions are actually cleared
- Verify SSO session status
Recommended Solutions
Option 1: Keycloak Configuration (Recommended)
- Enable Front-Channel Logout for all clients
- Configure Back-Channel Logout URLs
- This ensures all applications are notified of logout
Option 2: Clear SSO Session Cookie Explicitly
- After Admin API logout, redirect to Keycloak logout endpoint
- Use
kc_action=LOGOUTparameter (already implemented) - Ensure all client sessions are logged out first
Option 3: Use Keycloak Single Logout (SLO)
- Configure all clients to participate in SLO
- When dashboard logs out, all clients are automatically logged out
- Requires Keycloak configuration changes
Summary
Issue 1: 30-Minute Inactivity Timeout
- Status: Not implemented
- Reason: NextAuth doesn't track activity, only session age
- Solution: Client-side activity tracking + automatic logout
Issue 2: Applications Still Connected
- Status: Partially working
- Reason: SSO session cookie persists even after client sessions are cleared
- Solution: Keycloak configuration (Front-Channel Logout) or SLO