4.9 KiB
Phase 7.3: Security — ES256 Algorithm Upgrade - Discussion Log
Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
Date: 2026-06-05 Phase: 07.3-security-es256-algorithm-upgrade-inserted Areas discussed: Key format in env vars, Startup refresh-token rotation, Key generation workflow, JWT TTL / Remember Me
Key Format in Env Vars
Q1: How should P-256 PEM keys be stored in env vars?
| Option | Description | Selected |
|---|---|---|
| Base64-encoded | Single line, shell-safe, decoded in config.py | ✓ |
Escaped \n in .env |
python-dotenv expands \n; loader-dependent |
|
| Multiline .env block | Breaks in docker-compose environment: block |
User's choice: Base64-encoded
Notes: Standard 12-factor approach; no loader ambiguity.
Q2: Both keys required, or derive public from private at startup?
| Option | Description | Selected |
|---|---|---|
| Both required env vars | Clean separation; workers can hold public key only | ✓ |
| Private key only — derive public | Fewer env vars but more magic in config.py |
User's choice: Both required env vars
Q3: What happens to SECRET_KEY after ES256?
| Option | Description | Selected |
|---|---|---|
| Remove from JWT code | SECRET_KEY no longer used for signing; stays in env for future HMAC | ✓ |
| Repurpose as HMAC key for Phase 7.4 | Forward-compatible but couples phases |
User's choice: Remove SECRET_KEY from JWT code
Startup Refresh-Token Rotation
Q1: How to implement startup rotation?
| Option | Description | Selected |
|---|---|---|
| DELETE all refresh_tokens | Simple, one-shot; no schema change | |
| Bulk revoke (set revoked=True) | Cleaner audit trail; same user impact | ✓ |
| Let natural expiry handle it | Doesn't satisfy ROADMAP requirement |
User's choice: Bulk revoke (set revoked=True)
Q2: How to detect "first boot after ES256 migration"?
| Option | Description | Selected |
|---|---|---|
| Check system_settings table | Stores jwt_algorithm; idempotent on restart |
✓ |
| New env var JWT_TOKEN_GENERATION=N | Simple but requires operator bump on deploy | |
| One-time Alembic migration | Runs at migrate time, not startup |
User's choice: Check system_settings table (jwt_algorithm key)
Key Generation Workflow
Q1: How should developers generate the key pair?
| Option | Description | Selected |
|---|---|---|
| Python one-liner in README | Uses existing cryptography dep; no extra tooling |
✓ |
| openssl CLI command | Familiar to ops but multi-step, requires openssl | |
| Auto-generate on first boot | Convenient for dev; dangerous in prod (ephemeral keys) |
User's choice: Python one-liner documented in README
Q2: docker-compose key placeholder vs. .env reference?
| Option | Description | Selected |
|---|---|---|
| .env file reference only | Follows existing ${SECRET_KEY} pattern | ✓ |
| Placeholder comment in docker-compose | Helpful but could mislead |
User's choice: .env file reference only
JWT TTL / Remember Me
Q1 (freeform): What token should default to 12 hours?
User note: "JWT Tokens should only be valid for 12 hours and the user can opt-in to create a token which is valid for 30 days."
Asked for clarification on whether this applied to the access token or refresh token. User asked: "What do you think is the most secure way to handle tokens?"
Claude's recommendation: Keep access token at 15 min (CLAUDE.md requirement). Change refresh token default to 16–24 hours with explicit "remember me" opt-in for 30 days.
User's decision: 16 hours — covers a full workday; guarantees session is revoked overnight.
Q2: Fold "remember me" into Phase 7.3 or separate phase?
| Option | Description | Selected |
|---|---|---|
| Fold into Phase 7.3 | Already touching token creation code; incremental work | ✓ |
| Separate phase 7.5 | Keeps 7.3 purely as ES256 upgrade |
User's choice: Fold into Phase 7.3
Claude's Discretion
- PyJWT API form:
jwt.encode(payload, pem_str, algorithm="ES256")— PEM strings passed directly, no key object conversion needed - Bulk revoke via raw SQL
UPDATErather than ORM row-by-row — efficiency decision - "Stay signed in for 30 days" as checkbox label (clearer than "Remember me")
- system_settings key name:
jwt_algorithm, value"ES256"
Deferred Ideas
- Phase 7.4: Token fingerprinting / token binding (
fgpclaim = HMAC of User-Agent + Accept-Language) - Key rotation ceremony: Dual-key overlap process for rotating P-256 keys in production — deferred until production hardening milestone