Self-hosted Zitadel OIDC field guide — bundles working docker-compose, idempotent bootstrap (TS) and reset script, plus 42 documented quirks with proto-aligned examples verified against raw GitHub Zitadel v4.15.0 (FirstInstance, JWT/JWKS over self-signed HTTPS, login UI v1 branding, masterkey-via-flag, post-reset 401 storms, login UI v2 separate container in v4, API v2 idempotence via deterministic IDs, contextual orgId header→body, CreateApplication discriminator = oidcConfiguration top-level, per-service ListResponse field names, CreateAuthorization exige organizationId, quirk 28 Login UI v2 auto-provisioning quebrado em v4.15.0). v0.5.0 — CD cutover survival kit (quirks 29-32). v0.6.0 — Console UI human-user pitfalls (quirks 33-35). v0.7.0 — Production cutover from PR #9: quirk 36 backend extra_hosts hairpin NAT JWKS reload; quirk 37 frontend 401-storm defense-in-depth (3 layers — ApiClient dedupe + TanStack retry filter + apiclient:unauthorized listener with auth-route guard). v0.8.0 — smoke-e2e CI quirks from validade_bateria_estoque PR #10: quirk 38 `ZITADEL_FIRSTINSTANCE_PATPATH` bind mount EACCES cascading into misleading `unique_constraints_pkey`, quirk 39 password policy 4-class trap, quirk 40 `zitadel-login` healthcheck slow on small CI runners; plus the 'Smoke-e2e plumbing checklist for GHA'. NEW v0.9.0 — first real-browser smoke against the SPA↔backend↔Zitadel loop (sales_quote T150) surfaced two genuinely new pitfalls: quirk 41 — idempotent bootstrap creates initial user grants but does NOT reconcile existing ones when YAML evolves (adding a new app + role leaves pre-existing seed user grants stuck at day-0 `roleKeys`; JWT ships missing the new role; symptom collides with quirks 11/12/13/36/28 family but a brand-new user via the same bootstrap works fine — that asymmetry is the diagnostic); cure is search-then-PUT via Quirk 8 pattern. Quirk 42 — browser SPA → backend Express needs CORS or every preflight `OPTIONS` hits `authJwt` and 401s, mimicking the 401-storm family; key diagnostic asymmetry is `curl -H "Authorization: Bearer <JWT>"` returns 200 (no Origin → no preflight) while the browser fails 100%; MSW/supertest integration tests miss this entirely because neither issues a real preflight; cure is a minimal CORS middleware as FIRST app-level middleware, short-circuiting OPTIONS with 204 + headers; prevention is one Playwright spec that authenticates against real Zitadel and hits one `/api/*` endpoint. Plus a new `spa-recipes.md` recipe — 'E2E browser tests (Playwright) against self-signed Zitadel' — covering `ignoreHTTPSErrors: true` (browser-side counterpart of Quirk 12's `NODE_EXTRA_CA_CERTS`), conditional username fill for `login_hint`-prefilled flows in Login UI v1, and the `storageState`+`InMemoryWebStorage` reuse caveat (cookie survives, in-memory User doesn't, boot-time `signinSilent` iframe doesn't settle inside the 5s watchdog in headless Chromium). Quirks 30 and 39 extended with operational notes on `bootstrap.json` staleness after YAML edits and on `ZITADEL_SEED_USER_PASSWORD` env requirement outside `dev.sh` workflows. Includes v2.66→v4 upgrade runbook + API v1→v2 Connect protocol mapping.
Add the marketplace
/plugin marketplace add j0ruge/skills_commands_managerInstall plugins
/pluginRun these commands in Claude Code to add this plugin to your environment. The marketplace must be added before you can install its plugins.
From Marketplace