NeahNew/INACTIVITY_AND_LOGOUT_ANALYSIS.md

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

  1. 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 refetchInterval configured
  2. 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 maxAge is reached (30 days in your case)
  3. 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:

  1. Client-Side Activity Tracking:

    • Monitor user activity (mouse, keyboard, clicks)
    • Track last activity timestamp
    • Store in sessionStorage or localStorage
  2. Session Invalidation Logic:

    • Check inactivity period on each page interaction
    • Call signOut() if inactivity exceeds 30 minutes
    • Clear NextAuth session and Keycloak session
  3. Activity Reset on User Actions:

    • Reset inactivity timer on any user interaction
    • Update last activity timestamp
  4. SessionProvider Configuration:

    • Optionally configure refetchInterval to check session periodically
    • But this won't help with inactivity - it only refreshes the session

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:

  1. Create an InactivityHandler component
  2. Monitor user activity events (mousemove, keydown, click, scroll)
  3. Store last activity time in sessionStorage
  4. Check inactivity every minute (or on page focus)
  5. 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):

  1. Clear NextAuth cookies
  2. Clear Keycloak cookies (client-side attempt)
  3. Call /api/auth/end-sso-session (NEW)
    • Uses Keycloak Admin API: adminClient.users.logout({ id: userId })
  4. Sign out from NextAuth
  5. Redirect to Keycloak logout endpoint with id_token_hint

Problem Analysis

Why Applications Are Still Connected:

  1. 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
  2. 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
  3. 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
  4. Logout Endpoint Behavior:

    • Keycloak logout endpoint (/protocol/openid-connect/logout) with id_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

Root Cause

The SSO session cookie persists because:

  1. users.logout() Admin API method clears client sessions but may not clear SSO session cookie
  2. Keycloak logout endpoint only clears SSO session if it's the last client session
  3. If other applications have active sessions, the SSO session remains valid
  4. 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:

  1. Clear the SSO session cookie explicitly
  2. Or ensure all client sessions are logged out first
  3. Or use Keycloak's Single Logout (SLO) feature

Solution Requirements

To ensure applications are logged out:

  1. 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
  2. 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)
  3. 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:

  1. Admin API users.logout() is called
  2. All client sessions are logged out
  3. SSO session cookie may still exist
  4. Applications check SSO session cookie → still authenticated

When you redirect to Keycloak logout endpoint:

  1. Dashboard client session is cleared
  2. If it's the last client session, SSO session is cleared
  3. If other applications have active sessions, SSO session persists
  4. Applications can still authenticate using SSO session cookie

Verification Steps

To verify why applications are still connected:

  1. 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-session endpoint
  2. Check Keycloak session cookies:

    • After logout, check browser cookies for:
      • KEYCLOAK_SESSION
      • KEYCLOAK_SESSION_LEGACY
      • KEYCLOAK_IDENTITY
    • If these cookies still exist, SSO session is still active
  3. 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
  4. Check Keycloak Admin Console:

    • Navigate to: Users → [User] → Sessions
    • Check if sessions are actually cleared
    • Verify SSO session status

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=LOGOUT parameter (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