diff --git a/docs/404-and-session-fixes.md b/docs/404-and-session-fixes.md index a387536..9bb5379 100644 --- a/docs/404-and-session-fixes.md +++ b/docs/404-and-session-fixes.md @@ -5,6 +5,7 @@ 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 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 @@ -22,6 +23,11 @@ - 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 +### 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 ### 1. Fixed Expenses Page Metadata @@ -106,6 +112,28 @@ This prevents: - Added failure counting - only logs out after 3 consecutive failures - 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 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 5. **No immediate logout** - Session checks are properly coordinated and cached 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 @@ -132,6 +161,7 @@ This prevents: - 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 - Multiple failure tolerance prevents transient issues from logging users out +- Auth error handler differentiates between app and external service errors ## Timing Configuration Summary @@ -141,3 +171,12 @@ This prevents: - **Failure Tolerance**: 3 consecutive failures before logout 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. diff --git a/plugins/02.auth-error-handler.client.ts b/plugins/02.auth-error-handler.client.ts index 68ade63..0431405 100644 --- a/plugins/02.auth-error-handler.client.ts +++ b/plugins/02.auth-error-handler.client.ts @@ -25,18 +25,28 @@ export default defineNuxtPlugin(() => { statusText: response.statusText }) - // Handle authentication errors (401, 403) - if (response.status === 401 || response.status === 403) { + // 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) { + console.log('[AUTH_ERROR_HANDLER] Authentication error from app endpoint') handleAuthError({ statusCode: response.status, statusMessage: response.statusText, 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 - if (response.status === 404 && isProtectedRoute()) { - console.warn('[AUTH_ERROR_HANDLER] 404 on protected route, may be auth-related') + if (response.status === 404 && isProtectedRoute() && isAuthEndpoint) { + console.warn('[AUTH_ERROR_HANDLER] 404 on protected route from app endpoint, may be auth-related') // Check if session is still valid checkAndHandleSession() }