keycloak improve with build 8
This commit is contained in:
parent
61bc7d6809
commit
2b262b3b1c
366
SEPARATED_AUTHENTICATION_FLOWS_EXPLANATION.md
Normal file
366
SEPARATED_AUTHENTICATION_FLOWS_EXPLANATION.md
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
233
SESSION_DURATION_SECURITY_ANALYSIS.md
Normal file
233
SESSION_DURATION_SECURITY_ANALYSIS.md
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
# NextAuth Session Duration: 30 Days vs 4 Hours - Security Analysis
|
||||||
|
|
||||||
|
## Current Configuration
|
||||||
|
|
||||||
|
**Current Setting** (`app/api/auth/options.ts:190`):
|
||||||
|
```typescript
|
||||||
|
session: {
|
||||||
|
strategy: "jwt",
|
||||||
|
maxAge: 30 * 24 * 60 * 60, // 30 days (2,592,000 seconds)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Proposed Setting**:
|
||||||
|
```typescript
|
||||||
|
session: {
|
||||||
|
strategy: "jwt",
|
||||||
|
maxAge: 4 * 60 * 60, // 4 hours (14,400 seconds)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Analysis
|
||||||
|
|
||||||
|
### ✅ **Why 4 Hours is Better for Security**
|
||||||
|
|
||||||
|
1. **Reduced Attack Window**:
|
||||||
|
- **30 days**: If session is compromised, attacker has 30 days of access
|
||||||
|
- **4 hours**: If session is compromised, attacker has maximum 4 hours of access
|
||||||
|
- **Risk Reduction**: 99.4% reduction in maximum exposure time
|
||||||
|
|
||||||
|
2. **Industry Best Practices**:
|
||||||
|
- **NIST Guidelines**: Recommend session timeouts of 2-8 hours for high-security applications
|
||||||
|
- **OWASP**: Recommends session timeouts based on risk level (typically 2-8 hours)
|
||||||
|
- **Common Practice**: Most enterprise applications use 4-8 hour sessions
|
||||||
|
|
||||||
|
3. **Device Security**:
|
||||||
|
- **30 days**: Device left unattended = 30 days of potential unauthorized access
|
||||||
|
- **4 hours**: Device left unattended = maximum 4 hours of potential access
|
||||||
|
- **Better for**: Shared devices, public computers, unattended workstations
|
||||||
|
|
||||||
|
4. **Compliance**:
|
||||||
|
- Many security standards (ISO 27001, SOC 2) require reasonable session timeouts
|
||||||
|
- 30 days is often considered too long for compliance
|
||||||
|
- 4 hours aligns better with security compliance requirements
|
||||||
|
|
||||||
|
5. **Stolen Session Cookie**:
|
||||||
|
- If session cookie is stolen (XSS, MITM), shorter duration limits damage
|
||||||
|
- 4 hours gives attacker limited time to exploit
|
||||||
|
- 30 days gives attacker extensive time to exploit
|
||||||
|
|
||||||
|
### ⚠️ **Considerations & Trade-offs**
|
||||||
|
|
||||||
|
1. **User Experience Impact**:
|
||||||
|
- **30 days**: Users rarely need to re-authenticate (convenient)
|
||||||
|
- **4 hours**: Users need to re-authenticate every 4 hours (less convenient)
|
||||||
|
- **Impact**: Moderate - users will need to log in more frequently
|
||||||
|
|
||||||
|
2. **Token Refresh Behavior**:
|
||||||
|
- **Good News**: Your code already handles token refresh automatically
|
||||||
|
- **How it works**:
|
||||||
|
- When NextAuth session expires (4 hours), JWT callback runs
|
||||||
|
- If `accessToken` is expired, it calls `refreshAccessToken()`
|
||||||
|
- Uses `refreshToken` to get new tokens from Keycloak
|
||||||
|
- Session is automatically renewed (if refresh token is still valid)
|
||||||
|
- **Result**: Users may not notice the 4-hour expiration if they're active
|
||||||
|
|
||||||
|
3. **Keycloak Refresh Token Lifetime**:
|
||||||
|
- **Important**: Keycloak refresh tokens typically last 7-30 days
|
||||||
|
- **What this means**:
|
||||||
|
- NextAuth session expires after 4 hours
|
||||||
|
- But refresh token is still valid (e.g., 7 days)
|
||||||
|
- NextAuth automatically refreshes tokens
|
||||||
|
- User stays logged in seamlessly (if active)
|
||||||
|
- **Only expires if**: User is inactive for longer than refresh token lifetime
|
||||||
|
|
||||||
|
4. **Keycloak Session Alignment**:
|
||||||
|
- **Current Issue**: Keycloak sessions typically expire in 30 minutes to a few hours
|
||||||
|
- **With 4-hour NextAuth session**:
|
||||||
|
- Better alignment with Keycloak session timeouts
|
||||||
|
- Reduces session mismatch issues
|
||||||
|
- Iframe applications will have more consistent session state
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How It Will Work
|
||||||
|
|
||||||
|
### Session Lifecycle with 4-Hour maxAge
|
||||||
|
|
||||||
|
```
|
||||||
|
User logs in
|
||||||
|
↓
|
||||||
|
NextAuth creates JWT session (expires in 4 hours)
|
||||||
|
↓
|
||||||
|
User is active for 2 hours
|
||||||
|
↓
|
||||||
|
User makes request → NextAuth checks session
|
||||||
|
↓
|
||||||
|
Session still valid (< 4 hours) → Continue
|
||||||
|
↓
|
||||||
|
User is active for 3 hours
|
||||||
|
↓
|
||||||
|
User makes request → NextAuth checks session
|
||||||
|
↓
|
||||||
|
Session still valid (< 4 hours) → Continue
|
||||||
|
↓
|
||||||
|
User is active for 4.5 hours (session expired)
|
||||||
|
↓
|
||||||
|
User makes request → NextAuth checks session
|
||||||
|
↓
|
||||||
|
Session expired → JWT callback runs
|
||||||
|
↓
|
||||||
|
Checks accessToken expiration
|
||||||
|
↓
|
||||||
|
If accessToken expired → Calls refreshAccessToken()
|
||||||
|
↓
|
||||||
|
Uses refreshToken to get new tokens from Keycloak
|
||||||
|
↓
|
||||||
|
If refreshToken still valid → New session created (another 4 hours)
|
||||||
|
↓
|
||||||
|
User continues seamlessly (no re-authentication needed)
|
||||||
|
↓
|
||||||
|
If refreshToken expired → User must re-authenticate
|
||||||
|
```
|
||||||
|
|
||||||
|
### When User Must Re-authenticate
|
||||||
|
|
||||||
|
**User must re-authenticate if**:
|
||||||
|
1. **Inactive for longer than refresh token lifetime** (typically 7-30 days)
|
||||||
|
2. **Refresh token is revoked** (logout, admin action, security event)
|
||||||
|
3. **Keycloak session is invalidated** (logout from another application)
|
||||||
|
|
||||||
|
**User does NOT need to re-authenticate if**:
|
||||||
|
1. **Active within refresh token lifetime** (automatic token refresh)
|
||||||
|
2. **Session expires but refresh token is valid** (automatic renewal)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommendations
|
||||||
|
|
||||||
|
### ✅ **Recommendation: Implement 4-Hour Session**
|
||||||
|
|
||||||
|
**Reasons**:
|
||||||
|
1. ✅ **Significantly better security** (99.4% reduction in exposure window)
|
||||||
|
2. ✅ **Aligns with industry best practices** (NIST, OWASP)
|
||||||
|
3. ✅ **Better compliance** (meets security standards)
|
||||||
|
4. ✅ **Better alignment with Keycloak sessions**
|
||||||
|
5. ✅ **Minimal UX impact** (automatic token refresh handles renewal)
|
||||||
|
6. ✅ **Code already supports it** (token refresh mechanism exists)
|
||||||
|
|
||||||
|
### ⚠️ **Important Considerations**
|
||||||
|
|
||||||
|
1. **Verify Keycloak Refresh Token Lifetime**:
|
||||||
|
- Check Keycloak configuration for refresh token lifetime
|
||||||
|
- Ensure it's longer than 4 hours (typically 7-30 days)
|
||||||
|
- If shorter, users will need to re-authenticate frequently
|
||||||
|
|
||||||
|
2. **Monitor User Experience**:
|
||||||
|
- Track how often users need to re-authenticate
|
||||||
|
- If too frequent, consider increasing to 6-8 hours
|
||||||
|
- Balance security with usability
|
||||||
|
|
||||||
|
3. **Consider Activity-Based Extension**:
|
||||||
|
- Current implementation: Fixed 4-hour expiration
|
||||||
|
- Alternative: Extend session on activity (sliding window)
|
||||||
|
- Requires additional implementation (activity tracking)
|
||||||
|
|
||||||
|
4. **Keycloak Session Configuration**:
|
||||||
|
- Consider aligning Keycloak SSO session timeout with NextAuth
|
||||||
|
- Or ensure Keycloak session is longer than NextAuth session
|
||||||
|
- Prevents session mismatch issues
|
||||||
|
|
||||||
|
### 📋 **Implementation Checklist**
|
||||||
|
|
||||||
|
Before implementing:
|
||||||
|
|
||||||
|
- [ ] Verify Keycloak refresh token lifetime (should be > 4 hours)
|
||||||
|
- [ ] Test token refresh flow with 4-hour session
|
||||||
|
- [ ] Monitor user re-authentication frequency
|
||||||
|
- [ ] Consider user feedback on session duration
|
||||||
|
- [ ] Document the change for users (if needed)
|
||||||
|
- [ ] Update security documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comparison Table
|
||||||
|
|
||||||
|
| Aspect | 30 Days | 4 Hours | Winner |
|
||||||
|
|--------|---------|---------|--------|
|
||||||
|
| **Security** | Low (long exposure window) | High (short exposure window) | ✅ 4 Hours |
|
||||||
|
| **User Convenience** | High (rare re-authentication) | Medium (automatic refresh) | ✅ 30 Days |
|
||||||
|
| **Compliance** | Poor (too long) | Good (meets standards) | ✅ 4 Hours |
|
||||||
|
| **Risk Reduction** | Low | High (99.4% reduction) | ✅ 4 Hours |
|
||||||
|
| **Keycloak Alignment** | Poor (mismatch) | Good (better alignment) | ✅ 4 Hours |
|
||||||
|
| **Token Refresh** | Works | Works (same mechanism) | ✅ Tie |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
**Recommendation: Change to 4 hours**
|
||||||
|
|
||||||
|
**Why**:
|
||||||
|
- Significantly better security posture
|
||||||
|
- Aligns with industry best practices
|
||||||
|
- Better compliance with security standards
|
||||||
|
- Minimal UX impact (automatic token refresh)
|
||||||
|
- Better alignment with Keycloak session timeouts
|
||||||
|
- Code already supports it
|
||||||
|
|
||||||
|
**Implementation**:
|
||||||
|
- Simple change: `maxAge: 4 * 60 * 60`
|
||||||
|
- No code changes needed (token refresh already works)
|
||||||
|
- Monitor user experience and adjust if needed
|
||||||
|
|
||||||
|
**Alternative Consideration**:
|
||||||
|
- If 4 hours is too aggressive, consider 6-8 hours as a middle ground
|
||||||
|
- Still provides significant security improvement over 30 days
|
||||||
|
- Better user experience than 4 hours
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Verdict
|
||||||
|
|
||||||
|
**✅ Yes, change to 4 hours** - This is a good security practice that:
|
||||||
|
- Significantly reduces security risk
|
||||||
|
- Aligns with industry standards
|
||||||
|
- Has minimal UX impact (automatic refresh)
|
||||||
|
- Works with existing code
|
||||||
|
- Better aligns with Keycloak sessions
|
||||||
|
|
||||||
|
The only trade-off is slightly more frequent re-authentication for inactive users, but this is a reasonable security trade-off.
|
||||||
|
|
||||||
@ -187,7 +187,10 @@ export const authOptions: NextAuthOptions = {
|
|||||||
],
|
],
|
||||||
session: {
|
session: {
|
||||||
strategy: "jwt",
|
strategy: "jwt",
|
||||||
maxAge: 30 * 24 * 60 * 60, // 30 days
|
// 4 hours session timeout for security (reduces attack window from 30 days to 4 hours)
|
||||||
|
// Token refresh mechanism automatically renews session if user is active
|
||||||
|
// Users only need to re-authenticate if inactive longer than Keycloak refresh token lifetime
|
||||||
|
maxAge: 4 * 60 * 60, // 4 hours (14,400 seconds)
|
||||||
},
|
},
|
||||||
callbacks: {
|
callbacks: {
|
||||||
async jwt({ token, account, profile }) {
|
async jwt({ token, account, profile }) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user