NeahNew/LOGOUT_LOGIN_FLOW_TRACE.md

306 lines
9.7 KiB
Markdown

# Full Logout/Login Flow Trace
## Issue 1: No Credentials Asked After Logout/Login
### Current Flow Trace
#### Step 1: User Clicks Logout
```
Location: components/main-nav.tsx (line 364)
Action: onClick handler triggered
1. sessionStorage.setItem('just_logged_out', 'true')
2. document.cookie = 'logout_in_progress=true; path=/; max-age=60'
3. clearAuthCookies() - Clears NextAuth cookies client-side
4. signOut({ callbackUrl: '/signin?logout=true', redirect: false })
→ Calls NextAuth /api/auth/signout endpoint
→ Clears NextAuth session cookie server-side
5. window.location.replace(keycloakLogoutUrl)
→ Redirects to: ${KEYCLOAK_ISSUER}/protocol/openid-connect/logout
→ Parameters:
- post_logout_redirect_uri: /signin?logout=true
- id_token_hint: <ID token>
```
#### Step 2: Keycloak Logout Endpoint
```
Location: Keycloak Server
URL: ${KEYCLOAK_ISSUER}/protocol/openid-connect/logout
Expected Behavior:
- Keycloak should invalidate the session
- Keycloak should clear session cookies:
- KEYCLOAK_SESSION (main session cookie)
- KEYCLOAK_SESSION_LEGACY
- KEYCLOAK_IDENTITY (identity cookie)
- KEYCLOAK_IDENTITY_LEGACY
- AUTH_SESSION_ID
- KC_RESTART (if exists)
ACTUAL BEHAVIOR (PROBLEM):
- Keycloak logout endpoint with id_token_hint SHOULD clear cookies
- BUT: Keycloak might have SSO session that persists across clients
- OR: Cookies might not be cleared if domain/path mismatch
- OR: Keycloak might set new cookies during redirect
```
#### Step 3: Redirect Back to Signin
```
Location: app/signin/page.tsx
URL: /signin?logout=true
1. Component mounts
2. useEffect checks for logout flag (line 16-45)
- Sets isLogoutRedirect.current = true
- Removes 'just_logged_out' from sessionStorage
- Clears OAuth params from URL
3. Shows logout message with "Se connecter" button
4. User clicks "Se connecter" button (line 143-148)
- Calls: signIn("keycloak", { callbackUrl: "/" })
```
#### Step 4: Keycloak Authorization Request
```
Location: NextAuth → Keycloak
URL: ${KEYCLOAK_ISSUER}/protocol/openid-connect/auth
Parameters sent:
- client_id: KEYCLOAK_CLIENT_ID
- redirect_uri: ${NEXTAUTH_URL}/api/auth/callback/keycloak
- response_type: code
- scope: openid profile email roles
- state: <random state>
- code_challenge: (if PKCE enabled)
KEYCLOAK BEHAVIOR:
1. Keycloak receives authorization request
2. Keycloak checks for existing session cookies
3. IF Keycloak session cookies still exist:
→ Keycloak finds valid SSO session
→ Keycloak auto-authenticates user (no login prompt)
→ Keycloak redirects back with authorization code
4. IF Keycloak session cookies are cleared:
→ Keycloak shows login page
→ User enters credentials
→ Keycloak creates new session
→ Keycloak redirects back with authorization code
PROBLEM IDENTIFIED:
- Keycloak logout endpoint might not be clearing ALL session cookies
- OR: Keycloak has SSO session that persists (separate from client session)
- OR: Keycloak sets new cookies during the logout redirect process
- OR: Browser is preserving cookies due to SameSite/domain issues
```
### Root Cause Analysis
**Problem**: Keycloak SSO Session Persistence
Keycloak maintains two types of sessions:
1. **Client Session** (per OAuth client) - Cleared by logout endpoint
2. **SSO Session** (realm-wide) - May persist even after client logout
When you call:
```
GET /protocol/openid-connect/logout?id_token_hint=...&post_logout_redirect_uri=...
```
Keycloak behavior:
- ✅ Clears the **client session** for that specific OAuth client
- ✅ Invalidates tokens for that client
-**MIGHT NOT** clear the **SSO session** (realm-wide session)
-**MIGHT NOT** clear all session cookies if cookies are set with different domain/path
**Why SSO Session Persists:**
- Keycloak SSO session is realm-wide, not client-specific
- Multiple clients can share the same SSO session
- Logging out from one client doesn't necessarily log out from the realm
- The SSO session cookie (KEYCLOAK_SESSION) might persist
**When User Clicks "Se connecter":**
1. Redirects to Keycloak authorization endpoint
2. Keycloak checks for SSO session cookie
3. If SSO session cookie exists → Auto-authenticates (no credentials asked)
4. If SSO session cookie cleared → Shows login page
---
## Issue 2: Cannot Logout from Iframe Application
### Current Flow Trace
#### Step 1: User in Iframe Application
```
Location: Iframe application (e.g., /parole, /gite, etc.)
State:
- Dashboard has NextAuth session
- Keycloak session cookies exist
- Iframe app authenticated via Keycloak cookies
```
#### Step 2: User Clicks Logout in Iframe
```
Location: Iframe application's logout button
Action: Iframe app's logout handler
Possible Scenarios:
Scenario A: Iframe calls its own logout endpoint
- Iframe app might call: POST /api/logout (iframe app's endpoint)
- This might clear iframe app's session
- BUT: Keycloak session cookies might still exist
- Result: Iframe app logs out, but Keycloak session persists
Scenario B: Iframe calls Keycloak logout
- Iframe app might call: GET ${KEYCLOAK_ISSUER}/protocol/openid-connect/logout
- Keycloak clears session cookies
- BUT: NextAuth dashboard session still exists
- Result: Keycloak session cleared, but dashboard still logged in
Scenario C: Iframe doesn't have logout
- Iframe app might not have logout functionality
- User stuck in iframe with no way to logout
```
#### Step 3: What Happens After Iframe Logout
```
If iframe calls Keycloak logout:
1. Keycloak invalidates session
2. Keycloak clears session cookies
3. NextAuth dashboard still has valid JWT (30-day expiration)
4. NextAuth doesn't know Keycloak session was cleared
5. Dashboard widgets still show (using NextAuth session)
6. Iframe apps can't authenticate (Keycloak cookies cleared)
```
### Root Cause Analysis
**Problem**: No Communication Between Iframe and Dashboard
When iframe app logs out:
1. **Iframe app** calls Keycloak logout → Clears Keycloak cookies
2. **Dashboard** doesn't know about this → NextAuth session still valid
3. **Dashboard widgets** continue to work (using NextAuth session)
4. **Iframe apps** can't authenticate (Keycloak cookies gone)
**Why Dashboard Doesn't Know:**
- NextAuth session is independent of Keycloak session cookies
- NextAuth JWT has 30-day expiration
- No mechanism to detect Keycloak session invalidation from iframe
- Dashboard only detects invalidation when trying to refresh tokens
**Why Iframe Can't Logout Properly:**
- Iframe apps rely on Keycloak cookies for SSO
- If iframe calls Keycloak logout, it clears cookies
- But dashboard session persists
- If iframe doesn't call logout, user can't logout from iframe
- No way for iframe to trigger dashboard logout
---
## Key Findings
### Finding 1: Keycloak SSO Session Persistence
- **Issue**: Keycloak logout endpoint might not clear SSO session
- **Evidence**: User auto-authenticates without credentials after logout
- **Root Cause**: SSO session cookie persists after client logout
- **Impact**: Security issue - user should be asked for credentials
### Finding 2: Missing `prompt=login` Parameter
- **Issue**: When calling `signIn("keycloak")`, no `prompt=login` parameter is sent
- **Evidence**: Keycloak auto-authenticates if SSO session exists
- **Root Cause**: NextAuth Keycloak provider doesn't force login prompt
- **Impact**: User bypasses credential check
### Finding 3: Iframe Logout Isolation
- **Issue**: Iframe logout doesn't affect dashboard session
- **Evidence**: Dashboard widgets still show after iframe logout
- **Root Cause**: No communication mechanism between iframe and dashboard
- **Impact**: Inconsistent logout state
### Finding 4: No Cross-Origin Logout Communication
- **Issue**: Iframe can't trigger dashboard logout
- **Evidence**: User stuck in iframe after logout
- **Root Cause**: No postMessage or other communication mechanism
- **Impact**: Poor user experience
---
## Flow Diagram
### Current Logout Flow (Dashboard)
```
User clicks logout
Clear NextAuth cookies
Call NextAuth signOut()
Redirect to Keycloak logout
Keycloak clears client session
Keycloak MAY clear SSO session (not guaranteed)
Redirect to /signin?logout=true
User clicks "Se connecter"
Redirect to Keycloak auth
Keycloak checks SSO session
IF SSO session exists → Auto-authenticate (NO CREDENTIALS)
IF SSO session cleared → Show login page
```
### Current Iframe Logout Flow
```
User in iframe clicks logout
Iframe app calls logout (varies by app)
IF calls Keycloak logout:
→ Keycloak clears session cookies
→ Dashboard session still valid
→ Widgets still show
→ Iframe can't authenticate
IF doesn't call logout:
→ User stuck in iframe
→ No way to logout
```
---
## Recommendations
### For Issue 1 (No Credentials After Logout)
1. **Add `prompt=login` parameter** to Keycloak authorization request
- Forces Keycloak to show login page even if SSO session exists
- Location: `app/api/auth/options.ts` - KeycloakProvider authorization params
2. **Clear Keycloak SSO session explicitly**
- Add `kc_action=LOGOUT` parameter to logout URL
- Or call Keycloak admin API to end SSO session
3. **Clear Keycloak cookies client-side**
- After Keycloak logout redirect, clear any remaining Keycloak cookies
- Check for cookies with Keycloak domain
### For Issue 2 (Iframe Logout)
1. **Implement postMessage communication**
- Iframe sends logout message to parent
- Dashboard listens for logout messages
- Dashboard triggers logout when iframe logs out
2. **Detect Keycloak session invalidation**
- Poll Keycloak session status
- Detect when Keycloak cookies are cleared
- Automatically logout dashboard
3. **Unified logout endpoint**
- Create API endpoint that logs out both dashboard and Keycloak
- Iframe apps call this endpoint
- Ensures synchronized logout