e2c55556ac
- Replace symmetric SECRET_KEY with JWT_PRIVATE_KEY / JWT_PUBLIC_KEY (PEM) - Add iat claim to every token - Add expand_newlines validator in config for single-line .env PEM values - Add scripts/generate_jwt_keys.py key-generation helper - Update security-auditor agent JWT checklist with RS256 enforcement rules - Mark RS256 as done in TODO.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1.5 KiB
1.5 KiB
2026-04-13 — Switch JWT signing to RS256 (4096-bit RSA)
Timestamp: 2026-04-13T05:00:00
Summary
Replaced symmetric HS256 JWT signing with asymmetric RS256 using a 4096-bit RSA key pair. The private key signs tokens; the public key verifies them. Added iat (issued-at) claim to every token and a key-generation helper script.
Motivation
HS256 uses the same secret for signing and verification — if the key leaks, an attacker can forge arbitrary tokens. RS256 with a 4096-bit key eliminates this: the private key never leaves the backend process, and the public key can be distributed safely.
Files Added / Modified
scripts/generate_jwt_keys.py— generates a 4096-bit RSA key pair; outputs single-line PEM values ready to paste intobackend/.envbackend/app/core/config.py— replacedSECRET_KEY/ALGORITHM=HS256withJWT_PRIVATE_KEY,JWT_PUBLIC_KEY,ALGORITHM=RS256; addedexpand_newlinesvalidator to handle\n-escaped PEM in.envbackend/app/core/security.py—create_access_tokennow signs withJWT_PRIVATE_KEYand includesiatclaim;decode_access_tokenverifies withJWT_PUBLIC_KEYand pinsalgorithms=["RS256"].env.example— removedSECRET_KEY, addedJWT_PRIVATE_KEYandJWT_PUBLIC_KEYplaceholders with generation instructions.claude/agents/security-auditor.md— updated JWT checklist: added checks for wrong algorithm (non-RS256), symmetric key usage, and key-from-env requirement; updated policy noteTODO.md— added RS256 item to Auth/session security section (checked off)