Summary
Session security in src/services/auth_service.rs is a single static HS256 secret with structural gaps:
- No token revocation — logout, password change, or account compromise cannot invalidate already-issued access tokens; they remain valid until expiry.
- No refresh-token rotation or reuse detection — a stolen refresh token is replayable in parallel with the legitimate client indefinitely, and the theft is undetectable.
- No key rotation — one
JWT_SECRET forever; rotating it invalidates every session simultaneously and there is no kid-based overlap.
- No standard claims hygiene —
aud/iss validation and explicit clock-skew leeway are not enforced.
Task
- Refresh-token rotation with reuse detection: every refresh issues a new refresh token and invalidates the old one; presenting an already-rotated token (theft indicator) revokes the entire token family and forces re-authentication. Persist token families with device metadata (new migration).
- Access-token revocation: short-lived access tokens (≤15 min) plus a Redis denylist keyed by
jti, populated on logout / password change / admin revocation / family compromise, checked in middleware/auth.rs with a fail-closed policy and a latency budget (denylist check must be a single Redis round-trip).
kid-based key rotation: sign with the current key, verify against an active key set from config; an admin rotation flow allows overlap until old-key tokens age out. Document the runbook in docs/.
- Claims hygiene: enforce
iss, aud, nbf, bounded exp, and explicit leeway; reject algorithm confusion by pinning the algorithm allowlist at decode.
- Session management endpoints: list active sessions/devices for a user, revoke one, revoke all (wired into the existing admin surface).
- Tests: rotation happy path; reuse-detection kills the family (the critical test); revoked
jti rejected within one propagation round-trip; old-key verification during rotation overlap; algorithm-confusion attempt rejected; clock-skew boundary.
Acceptance criteria
PR requirements (mandatory)
- ✅ Your PR must pass all checks — PRs with failing or skipped checks will not be merged.
- 📸 You must attach a screenshot in the PR description demonstrating the result (for this issue: the reuse-detection test output and a demonstration of session revocation taking effect).
- 🔗 You must link this issue number in your PR description (e.g.
Closes #<issue-number>). PRs without a linked issue will not be reviewed.
Summary
Session security in
src/services/auth_service.rsis a single static HS256 secret with structural gaps:JWT_SECRETforever; rotating it invalidates every session simultaneously and there is nokid-based overlap.aud/issvalidation and explicit clock-skew leeway are not enforced.Task
jti, populated on logout / password change / admin revocation / family compromise, checked inmiddleware/auth.rswith a fail-closed policy and a latency budget (denylist check must be a single Redis round-trip).kid-based key rotation: sign with the current key, verify against an active key set from config; an admin rotation flow allows overlap until old-key tokens age out. Document the runbook indocs/.iss,aud,nbf, boundedexp, and explicit leeway; reject algorithm confusion by pinning the algorithm allowlist at decode.jtirejected within one propagation round-trip; old-key verification during rotation overlap; algorithm-confusion attempt rejected; clock-skew boundary.Acceptance criteria
aud/iss/algorithm pinning enforcedPR requirements (mandatory)
Closes #<issue-number>). PRs without a linked issue will not be reviewed.