mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
fix(auth): carry a generated secret in the session cookie, not the row id
The cookie was the Session row's cuid. cuid is built for collision- resistant identity across distributed writers, not for unguessability — it encodes a millisecond timestamp and a process-local counter and never touches a CSPRNG. A session cookie is a bearer credential and has to be unguessable, so it now carries 32 random bytes and only the HMAC of that value is stored, matching how api_tokens and refresh_tokens already hold their secrets. Compatibility is passive, and deliberately so. A backfill cannot help: the cookie already sitting in a browser is the cuid, and nothing we generate server-side can be pushed into it — backfilling would sign everyone out at deploy. Upgrading a row in place on first use loses to the parallel requests a single page load fires: each mints its own secret, one write wins, and the losers cannot re-emit the winner's secret because only a hash is stored, so the browser can end up holding a value the row does not honour. Instead, rows minted before the column keep a NULL token_hash and stay resolvable by id, and are denied the sliding-expiry extension so they drain within the 30-day session lifetime. Every login from this release forward is on a secret at once, and an id stops authenticating the moment its row holds one. Note for operators: API_TOKEN_HMAC_KEY now also keys session cookies, so rotating it signs browser sessions out as well as invalidating tokens. It is already Core-required, so no deployment gains a new prerequisite.
This commit is contained in:
1 parent
fd6a80a921
commit
a8b0365ca5
8 files changed
+516
-48
No files matched your search
@@ -47,11 +47,11 @@ echo "ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env
|
||||
echo "API_TOKEN_HMAC_KEY=$(openssl rand -hex 32)" >> .env
|
||||
```
|
||||
|
||||
| Variable | Purpose | Rotation cost |
|
||||
| -------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
||||
| `POSTGRES_PASSWORD` | Bundled Postgres password — used by both the `db` service and `DATABASE_URL` | Database restart + connection-string update |
|
||||
| `ENCRYPTION_KEY` | AES-256-GCM key for at-rest secrets (Withings tokens, AI provider keys, VAPID secrets) | Coordinated; see `docs/ops/encryption-key-rotation.md` |
|
||||
| `API_TOKEN_HMAC_KEY` | HMAC-SHA256 key for hashing Bearer API tokens before storage | Invalidates every issued `hlk_*` token |
|
||||
| Variable | Purpose | Rotation cost |
|
||||
| -------------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `POSTGRES_PASSWORD` | Bundled Postgres password — used by both the `db` service and `DATABASE_URL` | Database restart + connection-string update |
|
||||
| `ENCRYPTION_KEY` | AES-256-GCM key for at-rest secrets (Withings tokens, AI provider keys, VAPID secrets) | Coordinated; see `docs/ops/encryption-key-rotation.md` |
|
||||
| `API_TOKEN_HMAC_KEY` | HMAC-SHA256 key for hashing Bearer API tokens and web session cookies before storage | Invalidates every issued `hlk_*` token and signs out every browser session |
|
||||
|
||||
You do **not** edit `DATABASE_URL` on the bundled `docker-compose.yml`
|
||||
stack: compose constructs the connection string inside the `app`
|
||||
|
||||
Reference in new issue
Block a user