NeahNew/SEPARATED_AUTHENTICATION_FLOWS_EXPLANATION.md

367 lines
14 KiB
Markdown

# Why Dashboard and Applications Have Separated Authentication Flows
## Executive Summary
The dashboard and applications use **two completely separate authentication mechanisms** that operate independently:
1. **Dashboard**: Uses **NextAuth.js** with JWT-based sessions (30 days)
2. **Applications**: Use **Keycloak SSO** directly via browser cookies
This separation is why logging out from the dashboard doesn't automatically log you out from applications opened directly in the browser.
---
## Architecture Overview
### Two Independent Authentication Systems
```
┌─────────────────────────────────────────────────────────────┐
│ AUTHENTICATION LAYERS │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ DASHBOARD AUTH │ │ APPLICATION AUTH │ │
│ │ │ │ │ │
│ │ NextAuth.js │ │ Keycloak SSO │ │
│ │ (JWT Strategy) │ │ (Cookie-based) │ │
│ │ │ │ │ │
│ │ - Session: 30 days │ │ - Session: Variable │ │
│ │ - Stored in: Cookie │ │ - Stored in: Cookie │ │
│ │ - Domain: Dashboard │ │ - Domain: Keycloak │ │
│ │ - Independent │ │ - Independent │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │ │ │
│ └──────────┬───────────────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ KEYCLOAK │ │
│ │ (IdP Server) │ │
│ └────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## Why They're Separated
### 1. Different Authentication Purposes
**Dashboard Authentication (NextAuth.js)**:
- Purpose: Authenticate the **Next.js dashboard application**
- Method: OAuth 2.0 flow → Get tokens → Store in JWT
- Session Management: NextAuth manages its own session lifecycle
- Storage: Encrypted JWT in HTTP-only cookie on dashboard domain
- Duration: 30 days (configurable in `app/api/auth/options.ts`)
**Application Authentication (Keycloak SSO)**:
- Purpose: Authenticate **standalone applications** (not embedded in dashboard)
- Method: Direct Keycloak authentication via browser cookies
- Session Management: Keycloak manages SSO session lifecycle
- Storage: Keycloak session cookies on Keycloak domain
- Duration: Configured in Keycloak (typically 30 minutes to a few hours)
### 2. Different Session Storage Locations
**Dashboard Session**:
```
Cookie Name: next-auth.session-token
Domain: dashboard.example.com
Path: /
HttpOnly: Yes
Secure: Yes (if HTTPS)
SameSite: Lax
Content: Encrypted JWT containing:
- accessToken (Keycloak OAuth token)
- refreshToken (Keycloak refresh token)
- idToken (Keycloak ID token)
- User info (id, email, roles, etc.)
```
**Application Session**:
```
Cookie Name: KEYCLOAK_SESSION
Domain: keycloak.example.com (or configured domain)
Path: /
HttpOnly: Yes
Secure: Yes
SameSite: Lax or None (for cross-site)
Content: Keycloak session identifier
```
### 3. Different Authentication Flows
**Dashboard Flow**:
```
1. User visits dashboard → /signin
2. NextAuth redirects to Keycloak OAuth endpoint
3. Keycloak authenticates user
4. Keycloak redirects back with authorization code
5. NextAuth exchanges code for tokens
6. NextAuth creates JWT session
7. JWT stored in dashboard cookie
8. Dashboard uses JWT for authentication
```
**Application Flow** (when opened directly):
```
1. User visits application directly (not via dashboard)
2. Application checks for Keycloak session cookie
3. If cookie exists → User is authenticated (SSO)
4. If cookie doesn't exist → Redirect to Keycloak login
5. Keycloak authenticates user
6. Keycloak sets session cookie
7. Application uses cookie for authentication
```
---
## Why Dashboard Logout Doesn't Log Out Applications
### The Problem
When you log out from the dashboard:
1. **Dashboard logout process**:
- Clears NextAuth session cookie (`next-auth.session-token`)
- Calls Keycloak logout endpoint with `id_token_hint`
- Keycloak clears **client session** for dashboard OAuth client
- Keycloak may clear SSO session (if it's the last client session)
2. **What happens to applications**:
- Applications don't know about dashboard logout
- Applications still have Keycloak SSO session cookie
- Applications continue to work because they use Keycloak cookies, not NextAuth
### Technical Reasons
#### Reason 1: Different Cookie Domains
**Dashboard Cookie**:
- Domain: `dashboard.example.com`
- Cleared when dashboard logs out
- Applications can't access this cookie (different domain)
**Keycloak SSO Cookie**:
- Domain: `keycloak.example.com` (or configured domain)
- Not cleared by dashboard logout (unless SSO session is cleared)
- Applications can access this cookie (same domain as Keycloak)
#### Reason 2: Independent Session Lifecycles
**NextAuth Session**:
- Managed by NextAuth.js
- Lifecycle: Created on login → Valid for 30 days → Cleared on logout
- Independent of Keycloak SSO session
**Keycloak SSO Session**:
- Managed by Keycloak server
- Lifecycle: Created on login → Valid until timeout or explicit logout → Cleared on logout
- Independent of NextAuth session
#### Reason 3: Different Authentication Mechanisms
**Dashboard**:
- Uses OAuth 2.0 tokens (access token, refresh token)
- Tokens stored in NextAuth JWT
- Authentication: Validate JWT → Extract tokens → Use tokens for API calls
**Applications**:
- Use Keycloak session cookies directly
- No OAuth tokens involved
- Authentication: Check for Keycloak session cookie → If exists, user is authenticated
#### Reason 4: Keycloak SSO Session Persistence
**Keycloak maintains two types of sessions**:
1. **Client Session** (per OAuth client):
- Specific to each OAuth client (dashboard, app1, app2, etc.)
- Cleared when that specific client logs out
- Dashboard logout clears dashboard's client session
2. **SSO Session** (realm-wide):
- Shared across all clients in the realm
- Persists even after individual client logouts
- Only cleared when:
- All client sessions are logged out
- Explicit SSO session logout
- Session timeout
- Admin API logout
**When dashboard logs out**:
- Dashboard's client session is cleared ✅
- SSO session may persist if other applications have active sessions ❌
- Applications continue to work because SSO session is still valid ❌
---
## Current Logout Flow Analysis
### What Happens When You Log Out from Dashboard
```
Step 1: User clicks logout in dashboard
Step 2: Dashboard calls NextAuth signOut()
→ Clears: next-auth.session-token cookie
→ Clears: Dashboard's NextAuth session
Step 3: Dashboard calls /api/auth/end-sso-session
→ Uses Keycloak Admin API
→ Calls: adminClient.users.logout({ id: userId })
→ Clears: All client sessions for user
→ May clear: SSO session (if it's the last client session)
Step 4: Dashboard redirects to Keycloak logout endpoint
→ URL: ${KEYCLOAK_ISSUER}/protocol/openid-connect/logout
→ Parameters: id_token_hint, post_logout_redirect_uri
→ Clears: Dashboard's client session
→ May clear: SSO session (if it's the last client session)
Step 5: Keycloak redirects back to /signin?logout=true
→ Dashboard shows logout message
```
### What Happens to Applications
```
Applications opened directly in browser:
Step 1: Application checks for Keycloak session cookie
→ Cookie: KEYCLOAK_SESSION
→ Domain: keycloak.example.com
Step 2: If SSO session still exists:
→ Application finds valid SSO session cookie ✅
→ Application authenticates user automatically ✅
→ User remains logged in ❌
Step 3: If SSO session was cleared:
→ Application doesn't find session cookie ✅
→ Application redirects to Keycloak login ✅
→ User must log in again ✅
```
### Why Applications Stay Logged In
**Scenario 1: SSO Session Persists**
- Dashboard logout clears client sessions
- But SSO session cookie still exists
- Applications check SSO session cookie → Still valid → User stays logged in
**Scenario 2: Other Applications Have Active Sessions**
- If other applications are open in other tabs/windows
- They have active client sessions
- Keycloak won't clear SSO session (because other clients are still active)
- All applications stay logged in
**Scenario 3: Cookie Domain Mismatch**
- Dashboard tries to clear Keycloak cookies client-side
- But cookies are on different domain (keycloak.example.com)
- Browser security prevents clearing cross-domain cookies
- Applications keep their cookies → Stay logged in
---
## Why This Architecture Exists
### Historical/Design Reasons
1. **Legacy Applications**:
- Applications may have existed before the dashboard
- They were designed to use Keycloak directly
- Dashboard was added later as a wrapper/portal
2. **Separation of Concerns**:
- Dashboard: Portal/aggregator (doesn't need to know about app internals)
- Applications: Standalone services (don't depend on dashboard)
3. **Flexibility**:
- Applications can be accessed directly (not just via dashboard)
- Applications can be used independently
- Dashboard is optional, not required
4. **SSO Design**:
- Keycloak SSO is designed to work across multiple applications
- Logging out from one app shouldn't log out from all apps
- This is by design for SSO functionality
### Technical Constraints
1. **Cookie Security**:
- Browsers prevent cross-domain cookie access
- Dashboard can't directly clear Keycloak cookies (different domain)
- Must use Keycloak logout endpoint or Admin API
2. **Stateless vs Stateful**:
- NextAuth: Stateless (JWT, no server-side session)
- Keycloak: Stateful (server-side session, cookies)
3. **OAuth vs Direct Authentication**:
- Dashboard: Uses OAuth 2.0 (tokens)
- Applications: Use direct Keycloak authentication (cookies)
---
## What Would Be Needed for Unified Logout
To make dashboard logout also log out applications, you would need:
### Option 1: Keycloak Front-Channel Logout (Recommended)
- Configure all applications to participate in Front-Channel Logout
- When dashboard logs out, Keycloak notifies all registered applications
- Applications receive logout notification and clear their sessions
- **Requires**: Keycloak configuration + Application support
### Option 2: Keycloak Single Logout (SLO)
- Configure all applications to participate in SLO
- When one application logs out, all applications are logged out
- **Requires**: Keycloak configuration + Application support
### Option 3: Clear SSO Session Explicitly
- Use Keycloak Admin API to end SSO session
- This clears the realm-wide SSO session
- All applications lose their authentication
- **Current Implementation**: Partially implemented (`/api/auth/end-sso-session`)
- **Issue**: May not clear SSO session cookie if other clients are active
### Option 4: Application Logout Endpoints
- Each application exposes a logout endpoint
- Dashboard calls all application logout endpoints
- Applications clear their own sessions
- **Requires**: Application modifications + Dashboard coordination
---
## Summary
### Why They're Separated
1. **Different purposes**: Dashboard is a portal, applications are standalone services
2. **Different storage**: Dashboard uses NextAuth JWT, applications use Keycloak cookies
3. **Different domains**: Cookies are on different domains (security prevents cross-domain access)
4. **Different lifecycles**: NextAuth session (30 days) vs Keycloak SSO session (variable)
5. **SSO design**: Keycloak SSO is designed to persist across client logouts
### Why Dashboard Logout Doesn't Log Out Applications
1. **SSO session persists**: Keycloak SSO session may not be cleared
2. **Other active sessions**: If other applications are open, SSO session stays active
3. **Cookie domain**: Dashboard can't directly clear Keycloak cookies (different domain)
4. **Independent mechanisms**: Applications don't know about NextAuth session state
### The Solution
To achieve unified logout, you need to:
- Configure Keycloak Front-Channel Logout or SLO
- Ensure all applications participate in logout notifications
- Or use Admin API to explicitly end SSO session (current implementation attempts this)
The current implementation (`/api/auth/end-sso-session`) tries to clear the SSO session, but it may not work if:
- Other applications have active sessions
- SSO session cookie is on a different domain
- Keycloak configuration prevents SSO session clearing