From 9a83722273c70fe3df1b3d78f126aa7449fa35d1 Mon Sep 17 00:00:00 2001 From: gilesb Date: Fri, 9 Jan 2026 18:21:36 +0000 Subject: [PATCH] Document authentication and token revocation in README Co-Authored-By: Claude Opus 4.5 --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index dee43e7..5d5d2ee 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,43 @@ The server provides a web interface at the root URL: | `/recipe/{id}` | Recipe detail page | | `/media` | Browse cached media files | | `/auth` | Receive auth token from L2 | +| `/auth/revoke` | Revoke a token (called by L2 on logout) | | `/logout` | Log out | | `/download/client` | Download CLI client | +## Authentication + +L1 servers authenticate users via L2 (the ActivityPub registry). No shared secrets are required. + +### Configuration + +```bash +export L1_PUBLIC_URL=https://celery-artdag.rose-ash.com +``` + +### How it works + +1. User clicks "Attach" on L2's Renderers page +2. L2 creates a **scoped token** bound to this specific L1 +3. User is redirected to L1's `/auth?auth_token=...` +4. L1 calls L2's `/auth/verify` to validate the token +5. L2 checks: token valid, not revoked, scope matches this L1 +6. L1 sets a local cookie and records the token + +### Token revocation + +When a user logs out of L2, L2 calls `/auth/revoke` on all attached L1s. L1 maintains a Redis-based revocation list: + +- Revoked tokens stored in Redis with 30-day expiry +- Every authenticated request checks the revocation list +- Revoked tokens are immediately rejected + +### Security + +- **Scoped tokens**: Tokens are bound to a specific L1. A stolen token can't be used on other L1 servers. +- **L2 verification**: L1 verifies every token with L2, which checks its revocation table. +- **No shared secrets**: L1 doesn't need L2's JWT secret. + ## API Interactive docs: http://localhost:8100/docs