Summary
Auth signs JWTs with a single symmetric JWT__SECRET from .env (backend/auth/src/core/security.py). There is no kid header and no way to rotate without invalidating every outstanding token. Leaked secret means a full force-logout.
Changes
- Config accepts primary
JWT__PRIMARY_KID / JWT__PRIMARY_SECRET and a list of retired keys (JWT__RETIRED__<KID>).
backend/auth/src/core/security.py — sign with {"kid": primary_kid} in the header; verify by looking up kid in the union of primary + retired.
- Retired keys kept for the max refresh TTL (30 days) then removed.
- Document rotation procedure in
backend/auth/README.md.
Verification
- Start with key A as primary. Issue token T1.
- Rotate: make B primary, keep A retired. Issue T2.
- Both T1 and T2 validate; both survive a service restart.
- Remove A from retired list after TTL — T1 now rejected, T2 still good.
Summary
Auth signs JWTs with a single symmetric
JWT__SECRETfrom.env(backend/auth/src/core/security.py). There is nokidheader and no way to rotate without invalidating every outstanding token. Leaked secret means a full force-logout.Changes
JWT__PRIMARY_KID/JWT__PRIMARY_SECRETand a list of retired keys (JWT__RETIRED__<KID>).backend/auth/src/core/security.py— sign with{"kid": primary_kid}in the header; verify by looking upkidin the union of primary + retired.backend/auth/README.md.Verification