TASK-033: Remove session token from JSON response body
Fixes a critical security vulnerability where the session token was being returned in the JSON response body of POST /api/auth/login. This exposed the token to JavaScript, allowing malicious scripts to steal it and bypass the HttpOnly cookie protection. Changes: - Backend: Remove 'token' field from LoginResponse model (auth.py) - Backend: Update login() endpoint to return only 'expires_at' - Frontend: Update LoginResponse type to exclude 'token' field - Backend: Update test helper _login() to extract token from cookie - Backend: Update test cases to verify token is NOT in response body - Documentation: Add section 'Authentication Endpoints' in Backend-Development.md - Documentation: Update Web-Development.md to explain HttpOnly cookie benefits Security benefit: Session tokens are now only accessible via HttpOnly cookies, protected from JavaScript access, XSS attacks, and malicious third-party scripts. The frontend continues to use only the cookie for authentication. All auth tests pass (23 tests). Type checking and linting pass with zero errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -656,15 +656,17 @@ if (data.length > MAX_VISIBLE_BANS) { ... }
|
||||
|
||||
### Session Model
|
||||
|
||||
The authentication model is **cookie-based**:
|
||||
The authentication model is **cookie-based** for maximum security:
|
||||
|
||||
1. **Login:** The frontend sends the master password (SHA256-hashed) to `POST /api/auth/login`. The backend validates it, creates a session, and returns an HTTP response with a `Set-Cookie` header containing `bangui_session`.
|
||||
|
||||
2. **Requests:** All API requests automatically include the session cookie via `credentials: "include"` in the fetch options. The frontend does **not** send an Authorization header or token in the request body.
|
||||
2. **Response Body:** The login response contains **only** the session expiry timestamp (`expires_at`). **Importantly, the token is NOT returned in the JSON body.** This prevents malicious JavaScript from intercepting the token and storing it in localStorage or sessionStorage. The token is exclusively in the HttpOnly cookie, inaccessible to JavaScript.
|
||||
|
||||
3. **Session validity:** The backend is the **sole authority** on whether a session is valid. The frontend is authenticated when the backend accepts the request (returns 2xx) and is not authenticated when the backend rejects it (returns 401 or 403).
|
||||
3. **Requests:** All API requests automatically include the session cookie via `credentials: "include"` in the fetch options. The frontend does **not** send an Authorization header or token in the request body.
|
||||
|
||||
4. **Logout:** The frontend sends `POST /api/auth/logout`, and the backend invalidates the session and clears the cookie.
|
||||
4. **Session validity:** The backend is the **sole authority** on whether a session is valid. The frontend is authenticated when the backend accepts the request (returns 2xx) and is not authenticated when the backend rejects it (returns 401 or 403).
|
||||
|
||||
5. **Logout:** The frontend sends `POST /api/auth/logout`, and the backend invalidates the session and clears the cookie.
|
||||
|
||||
### Frontend Auth State
|
||||
|
||||
@@ -674,9 +676,13 @@ The authentication model is **cookie-based**:
|
||||
- The `sessionStorage` entry (`bangui_authenticated`) survives page refreshes within the same tab but is automatically cleared when the tab closes.
|
||||
- The session cookie persists according to the backend's cookie settings (typically for the duration of the browser session or as configured server-side).
|
||||
|
||||
### Why Not Token-Based?
|
||||
### Why HttpOnly Cookies?
|
||||
|
||||
The frontend previously stored JWT tokens in `sessionStorage` but never actually used them. The authentication model is entirely cookie-based (handled by the browser automatically), making stored tokens confusing and misleading. If token-based auth is needed in the future, the storage approach would need to change significantly (e.g., to include Authorization headers in all requests). For now, the only persistent state the frontend needs is the boolean `isAuthenticated` flag.
|
||||
HttpOnly cookies provide superior protection against XSS (Cross-Site Scripting) attacks compared to token-based storage:
|
||||
|
||||
- **localStorage / sessionStorage:** Accessible to any JavaScript on the page, including malicious scripts injected via third-party libraries, ads, or XSS vulnerabilities. A compromised script can steal the token, store it, and use it later or from another origin.
|
||||
- **Request body:** Requires explicit code to include in each request and is still visible to JavaScript before transmission.
|
||||
- **HttpOnly cookie:** Automatically included in requests by the browser, completely inaccessible to JavaScript, and cannot be stolen by client-side code. Cross-origin `fetch()` requests cannot automatically include cookies (unless `credentials: "include"` is set), further limiting attack surface.
|
||||
|
||||
### Error Handling
|
||||
|
||||
|
||||
Reference in New Issue
Block a user