feat: Update auth error handler to differentiate between app and external service 401 errors, preventing unnecessary session logouts

This commit is contained in:
Matt 2025-07-11 16:10:26 -04:00
parent eb1d853327
commit d71e2d348c
2 changed files with 53 additions and 4 deletions

View File

@ -5,6 +5,7 @@
1. **404 Error on Expenses Page** - The expenses page was returning a 404 error 1. **404 Error on Expenses Page** - The expenses page was returning a 404 error
2. **Session Expiration After 404** - Users were getting logged out after encountering the 404 error 2. **Session Expiration After 404** - Users were getting logged out after encountering the 404 error
3. **Immediate Session Expiration** - Users were getting logged out immediately after logging in 3. **Immediate Session Expiration** - Users were getting logged out immediately after logging in
4. **External Service 401 Errors** - 401 errors from external services (CMS, database) were logging users out
## Root Cause Analysis ## Root Cause Analysis
@ -22,6 +23,11 @@
- The auth refresh plugin's 2-minute periodic validation was conflicting with the 3-minute session cache - The auth refresh plugin's 2-minute periodic validation was conflicting with the 3-minute session cache
- Multiple concurrent session checks were causing race conditions - Multiple concurrent session checks were causing race conditions
### External Service 401 Cause
- The auth error handler was treating ANY 401 error as a session expiration
- When the CMS (`cms.portnimara.dev`) returned 401, it triggered a logout
- The handler didn't distinguish between auth API errors and external service errors
## Fixes Implemented ## Fixes Implemented
### 1. Fixed Expenses Page Metadata ### 1. Fixed Expenses Page Metadata
@ -106,6 +112,28 @@ This prevents:
- Added failure counting - only logs out after 3 consecutive failures - Added failure counting - only logs out after 3 consecutive failures
- Increased random offset to prevent thundering herd - Increased random offset to prevent thundering herd
### 7. Fixed Auth Error Handler
**File**: `plugins/02.auth-error-handler.client.ts`
Updated to only handle 401/403 errors from application endpoints:
```javascript
// Only handle authentication errors from our own API endpoints
const isAuthEndpoint = response.url && (
response.url.includes('/api/auth/') ||
response.url.includes('/api/') && !response.url.includes('cms.portnimara.dev') && !response.url.includes('database.portnimara.com')
)
// Handle authentication errors (401, 403) only from our API
if ((response.status === 401 || response.status === 403) && isAuthEndpoint) {
// Clear auth and redirect
} else if (response.status === 401 && !isAuthEndpoint) {
console.log('[AUTH_ERROR_HANDLER] Ignoring 401 from external service:', response.url)
// Don't clear auth for external service 401s
}
```
This prevents external service authentication errors from logging users out.
## Expected Results ## Expected Results
1. **Expenses page should now load properly** for users with sales or admin roles 1. **Expenses page should now load properly** for users with sales or admin roles
@ -114,6 +142,7 @@ This prevents:
4. **Consistent layout** across all dashboard pages 4. **Consistent layout** across all dashboard pages
5. **No immediate logout** - Session checks are properly coordinated and cached 5. **No immediate logout** - Session checks are properly coordinated and cached
6. **Stable session management** - No conflicts between different auth checking mechanisms 6. **Stable session management** - No conflicts between different auth checking mechanisms
7. **External service errors ignored** - 401 errors from CMS or database won't log users out
## Testing Steps ## Testing Steps
@ -132,6 +161,7 @@ This prevents:
- Session validation continues to work with the 3-minute cache + jitter to prevent race conditions - Session validation continues to work with the 3-minute cache + jitter to prevent race conditions
- Auth refresh plugin runs validation every 5 minutes to avoid cache conflicts - Auth refresh plugin runs validation every 5 minutes to avoid cache conflicts
- Multiple failure tolerance prevents transient issues from logging users out - Multiple failure tolerance prevents transient issues from logging users out
- Auth error handler differentiates between app and external service errors
## Timing Configuration Summary ## Timing Configuration Summary
@ -141,3 +171,12 @@ This prevents:
- **Failure Tolerance**: 3 consecutive failures before logout - **Failure Tolerance**: 3 consecutive failures before logout
This configuration ensures no timing conflicts between different auth mechanisms. This configuration ensures no timing conflicts between different auth mechanisms.
## External Service Integration
The auth error handler now properly handles errors from external services:
- **CMS errors** (cms.portnimara.dev) - 401 errors are logged but don't trigger logout
- **Database errors** (database.portnimara.com) - 401 errors are logged but don't trigger logout
- **App API errors** (/api/*) - 401/403 errors still trigger logout as expected
This allows the app to gracefully handle authentication failures with integrated services without disrupting the user's main session.

View File

@ -25,18 +25,28 @@ export default defineNuxtPlugin(() => {
statusText: response.statusText statusText: response.statusText
}) })
// Handle authentication errors (401, 403) // Only handle authentication errors from our own API endpoints
if (response.status === 401 || response.status === 403) { const isAuthEndpoint = response.url && (
response.url.includes('/api/auth/') ||
response.url.includes('/api/') && !response.url.includes('cms.portnimara.dev') && !response.url.includes('database.portnimara.com')
)
// Handle authentication errors (401, 403) only from our API
if ((response.status === 401 || response.status === 403) && isAuthEndpoint) {
console.log('[AUTH_ERROR_HANDLER] Authentication error from app endpoint')
handleAuthError({ handleAuthError({
statusCode: response.status, statusCode: response.status,
statusMessage: response.statusText, statusMessage: response.statusText,
data: response._data data: response._data
}) })
} else if (response.status === 401 && !isAuthEndpoint) {
console.log('[AUTH_ERROR_HANDLER] Ignoring 401 from external service:', response.url)
// Don't clear auth for external service 401s
} }
// Handle 404 errors that might be auth-related // Handle 404 errors that might be auth-related
if (response.status === 404 && isProtectedRoute()) { if (response.status === 404 && isProtectedRoute() && isAuthEndpoint) {
console.warn('[AUTH_ERROR_HANDLER] 404 on protected route, may be auth-related') console.warn('[AUTH_ERROR_HANDLER] 404 on protected route from app endpoint, may be auth-related')
// Check if session is still valid // Check if session is still valid
checkAndHandleSession() checkAndHandleSession()
} }