208 lines
6.9 KiB
Markdown
208 lines
6.9 KiB
Markdown
# SSO Flow Analysis - Confirmed Issues
|
|
|
|
## Browser Console Evidence
|
|
|
|
Based on the browser console error provided, here's what's happening:
|
|
|
|
### Confirmed Flow
|
|
|
|
1. **User logs out from Keycloak directly** (external application)
|
|
- Keycloak invalidates all tokens and session
|
|
|
|
2. **User accesses Dashboard**
|
|
- NextAuth session still exists (30-day expiration)
|
|
- JWT contains old, now-invalid tokens
|
|
- Token expiration check: `Date.now() < token.accessTokenExpires * 1000`
|
|
- If token hasn't expired by timestamp → JWT callback returns old token
|
|
- **Problem**: Token is invalid in Keycloak, but NextAuth doesn't validate it
|
|
|
|
3. **User navigates to iframe application**
|
|
- `ResponsiveIframe` component mounts
|
|
- Calls `GET /api/auth/refresh-keycloak-session`
|
|
- Refresh endpoint uses old `refreshToken` from session
|
|
- Keycloak responds: `{ error: 'invalid_grant', error_description: 'Token is not active' }`
|
|
- Returns 401 with `SessionInvalidated` error
|
|
|
|
4. **Redirect to Signin**
|
|
- `ResponsiveIframe` detects `SessionInvalidated`
|
|
- Redirects: `window.location.href = '/signin'`
|
|
- User lands on signin page
|
|
|
|
5. **Signin Process Starts**
|
|
- `app/signin/page.tsx` detects unauthenticated status
|
|
- Triggers: `signIn("keycloak", { callbackUrl: "/" })`
|
|
- User authenticates with Keycloak
|
|
- Gets NEW tokens from Keycloak
|
|
- NextAuth callback stores new tokens in JWT
|
|
|
|
6. **Storage Initialization Fails** ⚠️ **CONFIRMED ISSUE**
|
|
- Signin page detects session available
|
|
- Calls: `POST /api/storage/init`
|
|
- Storage endpoint tries to call: `createUserFolderStructure(session.user.id)`
|
|
- **Error**: `createUserFolderStructure is not a function`
|
|
- Storage initialization fails
|
|
- Signin page shows "Échec de l'initialisation"
|
|
- **Impact**: User might not be fully signed in, or session might not be complete
|
|
|
|
7. **User Returns to Iframe** (After Signin)
|
|
- Navigates to iframe application again
|
|
- `ResponsiveIframe` component mounts
|
|
- Calls refresh endpoint again
|
|
- **If storage init failed**: Session might not be fully established
|
|
- **If new session not ready**: Might still use old tokens
|
|
- Refresh fails again → Redirects to signin → Loop
|
|
|
|
## Confirmed Issues
|
|
|
|
### Issue 1: Storage Initialization Failure ✅ CONFIRMED
|
|
|
|
**Error**: `createUserFolderStructure is not a function`
|
|
|
|
**Location**: `app/api/storage/init/route.ts:16`
|
|
|
|
**Impact on SSO Flow**:
|
|
- Storage initialization is part of signin process
|
|
- If it fails, signin might not complete properly
|
|
- Session might not be fully established
|
|
- When user tries to access iframe, refresh endpoint might fail because:
|
|
- Session not complete
|
|
- Or still using old tokens if new session wasn't saved
|
|
|
|
**Evidence from Browser**:
|
|
```
|
|
Failed to initialize storage: "{\"error\":\"Failed to initialize storage\",\"details\":\"(0 , _lib_s3__WEBPACK_IMPORTED_MODULE_3__.createUserFolderStructure) is not a function\"}"
|
|
```
|
|
|
|
### Issue 2: Stale Token in NextAuth JWT ✅ CONFIRMED
|
|
|
|
**Problem**: When Keycloak session is invalidated externally:
|
|
- NextAuth JWT still contains old tokens
|
|
- JWT callback only checks expiration timestamp
|
|
- Doesn't validate with Keycloak that token is still valid
|
|
- Returns stale token until expiration timestamp is reached
|
|
|
|
**Evidence from Terminal**:
|
|
```
|
|
Failed to refresh Keycloak session: { error: 'invalid_grant', error_description: 'Token is not active' }
|
|
GET /api/auth/refresh-keycloak-session 401
|
|
```
|
|
|
|
### Issue 3: Race Condition After Re-authentication ✅ CONFIRMED
|
|
|
|
**Problem**: After user signs in again:
|
|
- New session is created
|
|
- But refresh endpoint might be called before:
|
|
- JWT callback has run with new account
|
|
- New tokens are stored in JWT
|
|
- Session cookie is updated in browser
|
|
- Result: Refresh endpoint still uses old tokens
|
|
|
|
**Evidence**: Multiple failed refresh attempts after signin
|
|
|
|
## Complete Flow Diagram (Confirmed)
|
|
|
|
```
|
|
1. User logs out from Keycloak (external)
|
|
↓
|
|
2. Keycloak invalidates:
|
|
- Session cookies ✅
|
|
- Refresh token ✅
|
|
- Access token ✅
|
|
↓
|
|
3. User accesses Dashboard
|
|
- NextAuth JWT has old tokens (not expired by timestamp)
|
|
- JWT callback returns old token (doesn't validate with Keycloak)
|
|
↓
|
|
4. User navigates to iframe
|
|
- ResponsiveIframe calls refresh endpoint
|
|
- Uses old refreshToken from session
|
|
↓
|
|
5. Keycloak rejects: "Token is not active"
|
|
↓
|
|
6. Refresh endpoint returns 401 SessionInvalidated
|
|
↓
|
|
7. Redirect to /signin
|
|
↓
|
|
8. User authenticates with Keycloak
|
|
- Gets NEW tokens
|
|
- NextAuth stores new tokens in JWT
|
|
↓
|
|
9. Storage initialization called
|
|
- ⚠️ FAILS: createUserFolderStructure not found
|
|
- Signin process incomplete
|
|
↓
|
|
10. User navigates to iframe again
|
|
- Refresh endpoint called
|
|
- ⚠️ Might still use old tokens (if new session not ready)
|
|
- OR: Session incomplete due to storage init failure
|
|
- Fails again → Redirects to signin
|
|
↓
|
|
11. LOOP or stuck state
|
|
```
|
|
|
|
## Root Causes (Confirmed)
|
|
|
|
1. **No Proactive Token Validation**
|
|
- NextAuth only checks expiration timestamps
|
|
- Doesn't validate tokens with Keycloak
|
|
- Stale tokens remain in JWT until timestamp expiration
|
|
|
|
2. **Storage Initialization Failure**
|
|
- Missing function: `createUserFolderStructure`
|
|
- Prevents complete signin initialization
|
|
- May cause session to be incomplete
|
|
|
|
3. **Race Condition**
|
|
- Refresh endpoint called before new session fully established
|
|
- Browser might send old session cookie
|
|
- JWT callback might not have run yet with new account
|
|
|
|
4. **No Session Invalidation on External Logout**
|
|
- When Keycloak session invalidated externally
|
|
- NextAuth doesn't know about it
|
|
- Continues using invalid tokens
|
|
|
|
## Impact on User Experience
|
|
|
|
**What User Sees**:
|
|
1. Logs out from Keycloak (external app)
|
|
2. Accesses Dashboard → Still logged in (NextAuth session valid)
|
|
3. Tries to access iframe application
|
|
4. Gets redirected to signin
|
|
5. Signs in again
|
|
6. Storage initialization fails (error message)
|
|
7. Tries to access iframe again
|
|
8. Gets redirected to signin again
|
|
9. **Stuck in loop or keeps getting disconnected**
|
|
|
|
## Recommendations
|
|
|
|
### Immediate Fixes Needed
|
|
|
|
1. **Fix Storage Initialization**
|
|
- Export `createUserFolderStructure` from `lib/s3.ts`
|
|
- Or remove storage init from signin flow if not critical
|
|
- Prevents signin from failing
|
|
|
|
2. **Proactive Token Validation**
|
|
- Before using tokens, validate with Keycloak
|
|
- Use Keycloak's userinfo endpoint to check token validity
|
|
- Clear session if token invalid
|
|
|
|
3. **Session Invalidation on Refresh Failure**
|
|
- When refresh fails with invalid_grant
|
|
- Immediately clear NextAuth session cookie
|
|
- Force complete re-authentication
|
|
|
|
4. **Delay Refresh After Signin**
|
|
- After redirect from signin, wait for session to be established
|
|
- Check session status before calling refresh endpoint
|
|
- Add retry logic with backoff
|
|
|
|
---
|
|
|
|
**Analysis Date**: 2024
|
|
**Status**: Issues Confirmed
|
|
**Evidence**: Browser console + Terminal logs
|
|
|