Files
kite/.planning/phases/07.3-security-es256-algorithm-upgrade-inserted/07.3-DISCUSSION-LOG.md
T

136 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 1624 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 `UPDATE` rather 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 (`fgp` claim = 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