# Authentication Flow Fixes ## Issues Fixed ### 1. Logout Loop Issue ✅ **Problem**: - User couldn't log out - infinite redirect loop - Sign-in page auto-triggered Keycloak login even when user was already authenticated - Keycloak session cookies weren't cleared, causing immediate re-authentication **Root Cause**: - `/signin` page had `useEffect(() => { signIn("keycloak") }, [])` that always triggered login - No check for existing authentication status - Keycloak logout endpoint was never called, leaving Keycloak cookies valid **Fix Applied**: 1. **Sign-in page** (`app/signin/page.tsx`): - Added check for existing session before triggering login - If user is already authenticated, redirect to home - Only trigger Keycloak login if status is "unauthenticated" 2. **Sign-out handler** (`components/auth/signout-handler.tsx`): - Now properly calls Keycloak logout endpoint - Uses ID token for proper logout - Clears both NextAuth and Keycloak cookies 3. **Main navigation logout** (`components/main-nav.tsx`): - Fixed to use `idToken` instead of `accessToken` for Keycloak logout - Proper logout flow with Keycloak endpoint --- ### 2. Iframe Applications Logging Out ✅ **Problem**: - Iframe applications were logging out even when user was still authenticated in dashboard - Desynchronization between NextAuth session and Keycloak session **Root Cause**: - Sign-out only cleared NextAuth cookies - Keycloak session cookies remained valid but could expire independently - Iframe apps rely on Keycloak cookies for SSO - When Keycloak cookies expired/invalidated, iframes logged out but dashboard stayed logged in **Fix Applied**: 1. **ID Token Storage** (`app/api/auth/options.ts`): - Now stores `idToken` from Keycloak in JWT - Exposes `idToken` in session object - Preserves ID token during token refresh 2. **Proper Keycloak Logout**: - Sign-out now calls Keycloak logout endpoint with `id_token_hint` - This properly invalidates Keycloak session and clears Keycloak cookies - Ensures synchronization between dashboard and iframe apps 3. **Type Definitions** (`types/next-auth.d.ts`): - Added `idToken` to Session and JWT interfaces - Type-safe access to ID token --- ## Changes Made ### Files Modified 1. **`app/api/auth/options.ts`** - Added `idToken` to JWT interface - Store `account.id_token` in JWT during initial authentication - Expose `idToken` in session callback - Preserve `idToken` during token refresh 2. **`app/signin/page.tsx`** - Added session status check - Prevent auto-login if already authenticated - Redirect authenticated users to home 3. **`components/auth/signout-handler.tsx`** - Call Keycloak logout endpoint with ID token - Proper logout flow that clears both NextAuth and Keycloak sessions 4. **`components/main-nav.tsx`** - Fixed logout button to use `idToken` instead of `accessToken` - Proper Keycloak logout flow 5. **`types/next-auth.d.ts`** - Added `idToken?: string` to Session interface - Added `idToken?: string` to JWT interface (both modules) --- ## How It Works Now ### Sign-In Flow (Fixed) ``` 1. User navigates to /signin 2. Check session status: - If authenticated → Redirect to / - If unauthenticated → Trigger Keycloak login 3. After Keycloak authentication: - Store tokens (access, refresh, ID token) - Initialize storage - Redirect to dashboard ``` ### Sign-Out Flow (Fixed) ``` 1. User clicks logout 2. Sign out from NextAuth (clears NextAuth cookies) 3. Call Keycloak logout endpoint: - URL: ${KEYCLOAK_ISSUER}/protocol/openid-connect/logout - Parameters: * post_logout_redirect_uri: /signin * id_token_hint: 4. Keycloak clears its session and cookies 5. Redirect to /signin (no auto-login loop) ``` ### Iframe SSO (Fixed) ``` 1. User authenticates in dashboard 2. Keycloak sets session cookies 3. Iframe apps read Keycloak cookies 4. When user logs out: - Keycloak logout endpoint is called - Keycloak cookies are cleared - Iframe apps lose access (synchronized logout) ``` --- ## Environment Variables Required Ensure these are set: ```bash # Required for logout NEXT_PUBLIC_KEYCLOAK_ISSUER=https://keycloak.example.com/realms/neah # Already required for authentication KEYCLOAK_CLIENT_ID=neah-dashboard KEYCLOAK_CLIENT_SECRET= KEYCLOAK_ISSUER=https://keycloak.example.com/realms/neah NEXTAUTH_URL=https://dashboard.example.com NEXTAUTH_SECRET= ``` **Important**: `NEXT_PUBLIC_KEYCLOAK_ISSUER` must be set for client-side logout to work. --- ## Testing Checklist ### Logout Flow - [ ] Click logout button - [ ] Should redirect to Keycloak logout - [ ] Should redirect back to /signin - [ ] Should NOT auto-login (no loop) - [ ] Should be able to manually log in again ### Sign-In Flow - [ ] Navigate to /signin when not authenticated - [ ] Should trigger Keycloak login - [ ] Navigate to /signin when already authenticated - [ ] Should redirect to / (no auto-login trigger) ### Iframe SSO - [ ] Log in to dashboard - [ ] Open iframe application - [ ] Should be automatically authenticated - [ ] Log out from dashboard - [ ] Iframe application should also lose authentication - [ ] Refresh iframe - should require login --- ## Additional Notes ### ID Token vs Access Token - **Access Token**: Used for API calls to Keycloak-protected resources - **ID Token**: Used for user identification and logout - **Refresh Token**: Used to get new access tokens The ID token is required for proper Keycloak logout. It tells Keycloak which session to invalidate. ### Cookie Synchronization The fix ensures that: 1. NextAuth cookies are cleared (dashboard logout) 2. Keycloak cookies are cleared (via logout endpoint) 3. Both happen in sequence, maintaining synchronization ### Token Refresh During token refresh, the ID token is preserved (Keycloak doesn't issue new ID tokens on refresh). This ensures logout continues to work even after token refreshes. --- ## Troubleshooting ### If logout still loops: 1. Check browser console for errors 2. Verify `NEXT_PUBLIC_KEYCLOAK_ISSUER` is set correctly 3. Check that Keycloak logout endpoint is accessible 4. Verify ID token is present in session: `console.log(session?.idToken)` ### If iframes still log out independently: 1. Check Keycloak cookie domain configuration 2. Verify iframe apps are configured to use same Keycloak realm 3. Check browser cookie settings (third-party cookies may be blocked) 4. Verify Keycloak session timeout settings --- **Date**: 2024 **Status**: ✅ Fixed **Version**: 1.0