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

2.3 KiB

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.