233 lines
8.4 KiB
Markdown
233 lines
8.4 KiB
Markdown
# 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`):
|
|
```typescript
|
|
session: {
|
|
strategy: "jwt",
|
|
maxAge: 30 * 24 * 60 * 60, // 30 days
|
|
}
|
|
```
|
|
|
|
**SessionProvider Configuration** (`components/providers.tsx`):
|
|
```typescript
|
|
<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
|
|
|
|
### 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=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
|
|
|