feat(security): load verify keys from auth JWKS
Build, Test & Push Core Service / quality-check (push) Successful in 40s
Build, Test & Push Core Service / docker (push) Successful in 1m24s

Core finds the key by the token kid and loads the JWKS again for an
unknown kid, at most every 10 s. JWT_PUBLIC_KEY is used only until the
first JWKS load works, so a key removed from the JWKS cannot verify
later. While that key still works, requests do not wait for a slow
Auth.
This commit is contained in:
lobo committed 2026-09-25 11:01:28 +02:00
1 parent 9fd552a785
commit 762b7898d3
8 files changed
+452 -60

No files matched your search

+8 -6
View File
@@ -35,10 +35,12 @@ To Be Played is split into three repositories:
## Authentication
Core never issues tokens. It verifies Auth's EdDSA (Ed25519) JWTs with the public key only (`JWT_PUBLIC_KEY`) and
reads `userId` and `steamId` from the claims. A token with a `typ` claim (for example a profile ticket) is rejected
on normal endpoints; the profile ticket is accepted only by `GET /api/public/profiles/library` in the
`X-Profile-Ticket` header.
Core never issues tokens. It verifies Auth's EdDSA (Ed25519) JWTs with public keys only. It loads them from Auth's
JWKS by the token's `kid` and loads again when a new `kid` shows up (at most every 10 seconds). Loaded keys stay
until Core restarts. `JWT_PUBLIC_KEY` is used only until the first JWKS load works. Core reads `userId` and
`steamId` from the claims.
A token with a `typ` claim (for example a profile ticket) is rejected on normal endpoints; the profile ticket is
accepted only by `GET /api/public/profiles/library` in the `X-Profile-Ticket` header.
## API
@@ -98,7 +100,8 @@ Configuration comes from environment variables:
| Variable | Purpose |
|---|---|
| `JWT_PUBLIC_KEY` | Auth's Ed25519 public key, Base64 of the X.509 DER bytes |
| `JWT_JWKS_URL` | Auth's `/.well-known/jwks.json` |
| `JWT_PUBLIC_KEY` | Ed25519 public key (Base64 of the X.509 DER bytes), used until the first JWKS load. Set this, `JWT_JWKS_URL`, or both |
| `STEAM_API_KEY` | Steam Web API key |
| `IGDB_CLIENT_ID`, `IGDB_CLIENT_SECRET` | Twitch app for IGDB (optional) |
| `DB_PASSWORD` | Local PostgreSQL password |
@@ -116,7 +119,6 @@ Runs unit, WebMvc, persistence and integration tests plus the ArchUnit rules. Ne
- Mood filter for the picker (needs genres or themes from IGDB).
- Sale alerts for wishlist games.
- Move `steam_adapter` DTOs out of `api`, then turn on strict module independence in ArchUnit.
- Fetch the public key from a JWKS endpoint in Auth instead of an environment variable.
## License