/** * Authentication Error Classification Helper * * Determines if an error is a genuine authentication failure that requires logout * vs other types of errors (authorization, validation, temporary issues, etc.) */ export interface AuthErrorClassification { shouldLogout: boolean errorType: 'token_expired' | 'token_invalid' | 'authorization' | 'other' | 'none' reason?: string } /** * Classifies an error response to determine if it's a true authentication failure * * @param error - The error response object * @returns Classification indicating if logout is required */ export function classifyAuthError(error: any): AuthErrorClassification { const status = Number(error?.status ?? error?.statusCode ?? 0) const message = (error?.message ?? error?.detail ?? error?.statusMessage ?? '').toLowerCase() // Not an auth-related error at all if (status !== 401 && status !== 403 && status !== 407) { return { shouldLogout: false, errorType: 'none' } } // Check for specific authentication failure indicators const tokenExpiredIndicators = [ 'token expired', 'token has expired', 'jwt expired', 'session expired', 'authentication expired' ] const tokenInvalidIndicators = [ 'invalid token', 'token invalid', 'invalid credentials', 'authentication failed', 'invalid authentication', 'token not found', 'no token provided', 'missing token', 'malformed token', 'token verification failed' ] const authorizationIndicators = [ 'forbidden', 'access denied', 'insufficient permissions', 'not authorized', 'permission denied', 'unauthorized access', 'requires permission' ] // Check message content for specific error types if (tokenExpiredIndicators.some(indicator => message.includes(indicator))) { return { shouldLogout: true, errorType: 'token_expired', reason: 'Token has expired and cannot be refreshed' } } if (tokenInvalidIndicators.some(indicator => message.includes(indicator))) { return { shouldLogout: true, errorType: 'token_invalid', reason: 'Token is invalid or authentication failed' } } if (authorizationIndicators.some(indicator => message.includes(indicator))) { return { shouldLogout: false, errorType: 'authorization', reason: 'User is authenticated but lacks permission for this resource' } } // Default behavior based on status code // 401: Usually means authentication failed - should logout // 403: Usually means authorization failed - should NOT logout // 407: Proxy authentication required - should logout if (status === 401 || status === 407) { return { shouldLogout: true, errorType: 'token_invalid', reason: `Received ${status} status without specific error message` } } if (status === 403) { return { shouldLogout: false, errorType: 'authorization', reason: 'Access forbidden - likely a permissions issue, not authentication' } } return { shouldLogout: false, errorType: 'other', reason: 'Error does not indicate authentication failure' } } /** * Checks if an error should trigger a logout * * @param error - The error response object * @returns true if the user should be logged out */ export function shouldLogoutOnError(error: any): boolean { return classifyAuthError(error).shouldLogout } export default classifyAuthError