Files
reactbin/specs/004-jwt-bearer-auth/contracts/api.md
agatha 5fbbc1e67f Feat: Implement JWT bearer token authentication
Protects image upload, delete, and tag-update endpoints behind
Bearer token auth. Public read endpoints remain open. Angular SPA
gains a login page, auth interceptor, and route guard for /upload.

- JWTAuthProvider (HS256, sub/iat/exp, secrets.compare_digest)
- POST /api/v1/auth/token login endpoint
- require_auth FastAPI dependency on all write routes
- AuthService, LoginComponent, authInterceptor, authGuard
- Detail page hides write controls for unauthenticated visitors
- 43 unit tests passing; integration tests require Docker stack

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 19:12:38 +00:00

3.1 KiB
Raw Blame History

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": "<human message>", "code": "<machine code>" }.


New Endpoint

POST /api/v1/auth/token

Issues a bearer token for the owner after verifying credentials.

Request

Content-Type: application/json

{
  "username": "<string>",
  "password": "<string>"
}

Both fields are required. A missing or empty field returns 422.

Success response200 OK

{
  "access_token": "<jwt-string>",
  "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 <access_token>

401 response shape (returned by all three protected endpoints when authentication fails):

{
  "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 13 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)