NeahNew/LOGOUT_LOGIN_FLOW_TRACE.md

9.7 KiB

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