# API Contracts: JWT Bearer Token Authentication **Feature**: `004-jwt-bearer-auth` | **Date**: 2026-05-03 All routes remain under `/api/v1/`. Error responses use the existing envelope: `{ "detail": "", "code": "" }`. --- ## New Endpoint ### `POST /api/v1/auth/token` Issues a bearer token for the owner after verifying credentials. **Request** ``` Content-Type: application/json { "username": "", "password": "" } ``` Both fields are required. A missing or empty field returns `422`. **Success response** — `200 OK` ```json { "access_token": "", "token_type": "bearer", "expires_in": 86400 } ``` `expires_in` reflects the configured `JWT_EXPIRY_SECONDS` value. **Failure responses** | Status | Code | When | |---|---|---| | `401` | `invalid_credentials` | Username or password is wrong | | `422` | (FastAPI default) | Missing or malformed request body | --- ## Changed Endpoints — Access Control The following endpoints now require a valid bearer token. Requests without a token, or with an invalid/expired token, receive a `401`. | Method | Path | Was | Now | |---|---|---|---| | `POST` | `/api/v1/images` | Public | **Protected** | | `DELETE` | `/api/v1/images/{id}` | Public | **Protected** | | `PATCH` | `/api/v1/images/{id}/tags` | Public | **Protected** | **Bearer token transmission** The client MUST include the token in the `Authorization` header: ``` Authorization: Bearer ``` **401 response shape** (returned by all three protected endpoints when authentication fails): ```json { "detail": "Authentication required", "code": "unauthorized" } ``` --- ## Unchanged Endpoints — Remain Public The following endpoints require no token and must continue to accept requests without an `Authorization` header: | Method | Path | Description | |---|---|---| | `GET` | `/api/v1/images` | List / filter images | | `GET` | `/api/v1/images/{id}` | Get image metadata | | `GET` | `/api/v1/images/{id}/file` | Serve original image | | `GET` | `/api/v1/images/{id}/thumbnail` | Serve image thumbnail | | `GET` | `/api/v1/tags` | List / search tags | | `GET` | `/api/v1/health` | Health check | Sending a token on these endpoints is harmless (the server ignores it) but is not required. --- ## Token Validation Rules The API validates tokens using the following rules, in order: 1. The `Authorization` header value MUST begin with `Bearer ` (case-sensitive). 2. The token MUST be a valid HS256-signed JWT (verified against `JWT_SECRET_KEY`). 3. The `exp` claim MUST be in the future (at time of request receipt). 4. Any failure in steps 1–3 returns `401 unauthorized`. --- ## UI Route Contracts These are Angular SPA routes affected by this feature. | Route | Guard | Behaviour | |---|---|---| | `/login` | None | Login form; redirects to `returnUrl` or `/` on success | | `/upload` | `authGuard` | Redirects to `/login?returnUrl=/upload` if not authenticated | | `/images/:id` | None | Always accessible; tag-edit and delete controls visible only when authenticated | | `/` | None | Always accessible (library) |