pvm/docs/TODO_SECURITY.md
Mikkel Georgsen a22ba48709 Add Zitadel OIDC setup, SMTP config, and security fixes
- Add setup-zitadel.sh: idempotent script that creates PVM project
  and OIDC app via Zitadel Management API using machine user PAT
- Add machine user + PAT auto-generation to docker-compose via
  FIRSTINSTANCE env vars with bind-mounted machinekey directory
- Add SMTP configuration for email sending (verification, password reset)
- Fix JWT algorithm confusion attack: restrict to RS256/384/512 only
- Add docs/TODO_SECURITY.md tracking review findings
- Update .env.example files with correct local dev URLs
- Add docker/machinekey/ to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:34:44 +01:00

37 lines
2.1 KiB
Markdown

# Security & Technical Debt
Items identified during code review that should be addressed before production.
## High Priority
### Token refresh logic in SvelteKit (`apps/dashboard/src/auth.ts`)
The JWT callback stores `expiresAt` and `refreshToken` but never checks expiry or initiates a refresh. Auth.js does not auto-refresh tokens. Without this, users get silently logged out when their access token expires (typically 5-15 minutes for Zitadel).
**Fix:** Add expiry check in the `jwt` callback and use `refreshToken` to obtain a new access token when expired.
### JWKS cache thundering herd (`crates/pvm-auth/src/jwks.rs`)
When the cache expires, every concurrent request sees stale cache and calls `refresh()` simultaneously. The `RwLock` serializes writes but each request still makes an HTTP call before acquiring the lock.
**Fix:** Add a "refresh-in-progress" flag or use double-checked locking so only one request triggers the refresh while others wait.
## Medium Priority
### `trustHost: true` in auth.ts
Disables CSRF origin check in Auth.js. Required for local dev behind localhost, but must be removed or made conditional for production.
### `devMode: true` in OIDC app config (`docker/setup-zitadel.sh`)
Disables redirect URI validation in Zitadel. The setup script is dev-only, but if a similar script is used for production, this must be `false`.
### Custom login UI
Replace the default Zitadel login v1 UI with a fully custom login/signup flow built into the SvelteKit dashboard using Zitadel's Session API. Includes: login, signup, password reset, 2FA flows. Must match PVM visual design.
## Low Priority
### Shell script JSON parsing (`docker/setup-zitadel.sh`)
Uses `grep -o` and `cut` to extract JSON fields. Fragile if JSON format changes. Consider using `jq` with a fallback.
### PAT expiration
Machine user PAT expires 2030-01-01. Fine for dev, but production should use shorter-lived credentials.
### Running Zitadel as root (`docker-compose.dev.yml`)
`user: "0"` is required for `start-from-init` to write the PAT file. Dev-only concern — production deployment should use proper volume permissions.