pvm/docs/TODO_SECURITY.md
Mikkel Georgsen ed0578cd07 Address security/tech debt: token refresh, JWKS thundering herd, config safety, jq migration
- Add token refresh logic in Auth.js JWT callback with 60s expiry buffer
- Fix JWKS cache thundering herd with Mutex + double-checked locking
- Make trustHost conditional (dev-only) via SvelteKit's $app/environment
- Make devMode conditional on ZITADEL_PRODUCTION env var in setup script
- Replace fragile grep/cut JSON parsing with jq in setup-zitadel.sh
- Add OIDC_GRANT_TYPE_REFRESH_TOKEN to Zitadel OIDC app grant types
- Update TODO_SECURITY.md: mark resolved items, add RefreshAccessTokenError frontend handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:17:42 +01:00

47 lines
2.3 KiB
Markdown

# Security & Technical Debt
Items identified during code review that should be addressed before production.
## High Priority
### Social login providers (Zitadel IDP configuration)
Configure external identity providers in Zitadel so users can sign in with social accounts. Each requires creating OAuth2 credentials with the respective provider and registering them in Zitadel Console → Settings → Identity Providers.
1. **Google** — Google Cloud Console OAuth 2.0 Client ID
2. **Apple** — Apple Developer Sign in with Apple service ID + key
3. **Facebook** — Meta for Developers app with Facebook Login product
No code changes needed in the SvelteKit app — Zitadel's login page shows social buttons automatically once IDPs are configured.
## Medium Priority
### 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.
### Frontend handling of RefreshAccessTokenError
The session now exposes `session.error` when token refresh fails, but no frontend component checks this to redirect the user to `/login`. Add a check in the dashboard layout or a client-side hook.
## Low Priority
### 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.
## Resolved
### ~~Token refresh logic~~ (done)
Added expiry check + refresh in `auth.ts` JWT callback. Uses `refreshToken` to call Zitadel's token endpoint with `client_secret_basic`.
### ~~JWKS cache thundering herd~~ (done)
Added `tokio::sync::Mutex` refresh lock with double-checked locking in `jwks.rs`. Only one request triggers HTTP refresh; others wait.
### ~~`trustHost: true`~~ (done)
Changed to `trustHost: dev` — uses SvelteKit's `$app/environment` to enable only in dev mode.
### ~~`devMode: true`~~ (done)
Made conditional on `ZITADEL_PRODUCTION` env var in `setup-zitadel.sh`.
### ~~Shell script JSON parsing~~ (done)
Replaced all `grep -o`/`cut` with `jq -r` in `setup-zitadel.sh`. Added jq preflight check.