fix: prevent silent auth error swallowing in fetch error utility

- Add setAuthErrorHandler() registration mechanism to utils/fetchError.ts
- Implement fallback logging when auth errors (401/403) occur without registered handler
- Update AuthProvider to register both API client and fetch error handlers
- Ensure auth errors are handled deterministically at multiple layers
- Add comprehensive tests for auth error handler registration and fallback logging
- Update Web-Development.md documentation with auth error handling contract

Fixes issue #21: Silent auth errors are now caught and logged if the handler is not
registered, preventing actionable errors from being silently swallowed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-28 09:45:08 +02:00
parent ca23858946
commit 72c4a0ed04
5 changed files with 154 additions and 27 deletions

View File

@@ -20,6 +20,17 @@
* The `isAuthenticated` state persists in `sessionStorage` to survive page
* refreshes within the browser tab but is cleared on tab close. The session
* cookie itself persists according to the backend's cookie settings.
*
* **Auth Error Handling:**
* AuthProvider registers two auth error handlers to ensure that 401/403 errors
* are never silently swallowed:
* - `setUnauthorizedHandler()` in `api/client.ts` — handles auth errors from the
* API client layer before they reach hooks
* - `setAuthErrorHandler()` in `utils/fetchError.ts` — handles auth errors that
* reach hooks and ensures deterministic error handling with fallback logging
*
* This dual-handler approach ensures auth errors are caught and handled at
* multiple layers, preventing silent error loss regardless of where the error occurs.
*/
import React, {
@@ -32,6 +43,7 @@ import React, {
import { useNavigate } from "react-router-dom";
import * as authApi from "../api/auth";
import { setUnauthorizedHandler } from "../api/client";
import { setAuthErrorHandler } from "../utils/fetchError";
import { SessionValidationLoading } from "../components/SessionValidationLoading";
import { useSessionValidation } from "../hooks/useSessionValidation";
@@ -103,8 +115,12 @@ export function AuthProvider({
setUnauthorizedHandler((): void => {
handleSessionExpired();
});
setAuthErrorHandler((): void => {
handleSessionExpired();
});
return (): void => {
setUnauthorizedHandler(null);
setAuthErrorHandler(null);
};
}, [handleSessionExpired]);