Repository navigation
Conversation
With GUARD_IDENTITY=1 the fork no longer runs its own OIDC client: guard is the relying party and owns the sessions, and checkAuth verifies the x-bastion-identity JWT with @metsaapp/edgeauth on every API request, mapping the Zitadel subject to the Umami user linked through oidc_issuer/oidc_subject (GUARD_USER_ISSUER keeps existing users). The role comes from the identity's role keys (GUARD_ROLE_*); no mapped role is 401, unreachable guard keys are 503. Password login and Umami's own session tokens are refused behind guard; share tokens keep working. Login and logout go to /.well-known/bastion/. Removes the OIDC authorize/callback/logout routes, /sso-complete, the OIDC_* settings and openid-client. The server refuses to start with GUARD_IDENTITY set but incomplete. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MwB9uUtkK8BFT7ZGoXwX9u
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
COR-1082 (project "Central auth in guard"). Guard becomes the only OIDC relying party for insights.metsa.app. It owns the sessions and their revocation, and it sends a short-lived ES256 identity JWT in
x-bastion-identitywith each request it lets through. This PR makes the fork use that JWT for sign-in, behind one env flag,GUARD_IDENTITY=1./api/*with a Bearer token it keeps in localStorage. Behind guard there is no such token. Instead,checkAuth(src/lib/auth.ts, whichparseRequestuses) verifies the identity header with@metsaapp/edgeauthon every API request and turns it into the Umami user.subis looked up throughuser.oidc_issuer/user.oidc_subject, underGUARD_USER_ISSUER, which must equal the oldOIDC_ISSUER. A user is created on first sight and is suffixed if the username is taken. Opt-in auto-link happens only on a verified email. An existing user's username is never changed, because the identity has nopreferred_username.GUARD_ROLE_ADMIN=umami-admin→ admin). An identity with no mapped role gets 401 (fail closed).GUARD_IDENTITYis set butPLATFORM_KIT_EDGEAUTH_AUDIENCES,GUARD_USER_ISSUERor a role mapping is missing./loginoffers one button that goes to/.well-known/bastion/login?return_to=/. It never redirects by itself, so a signed-in user without a role can't get stuck in a redirect loop./logoutgoes to/.well-known/bastion/logout.Removed
src/app/api/auth/oidc/{authorize,callback,logout}(routes and OpenAPI contracts),/sso-completeand its handoff cookie, the discovery, PKCE and login-state code insrc/lib/oidc.ts, and theopenid-clientdependency.OIDC_*env vars and theumami-oidcclient id and secret. The OIDC strings in en-US messages and the regenerated api-client types are also gone./api/auth/loginanswers 403 and Umami session tokens are not accepted. Guard gates every dashboard path, so a password login could only be reached by someone who already holdsumami-admin. It would add a second credential and no availability, because when guard or Zitadel is down the host is unreachable anyway.GUARD_IDENTITYand port-forward to the pod. Without the flag the fork falls back to upstream's password login, so a local account with a password (the seededadmin) still works.Kept
APP_SECRETand 2FA are kept.auth.*keys stop being written behind guard.src/lib/oidc.tsis renamed tosrc/lib/guard-identity.tsand keeps only the mapping code.ENG-1068 / COR-1068 (Umami on NATS KV): it has already landed (Done). Had this PR landed first, ENG-1068 would have shrunk to nothing for sessions, since revocation now lives in guard. The cache still uses the bucket, so that work stays useful.
Docs: the README's OIDC section is replaced by "Sign-in through guard".
Tests
pnpm test(vitest),src/lib/guard-identity.test.tsandsrc/lib/auth.guard.test.tsuse ES256 identity JWTs minted locally (node:crypto key and a JWKS served on 127.0.0.1, helper insrc/test/edgeauth.ts) and verified by the real verifier. They cover:login/route.test.ts)instrumentation.test.ts)src/app/mcp/route.test.tsneeds the built@umami/mcpand api-client packages.src/lib/two-factor/backup-codes.test.tshits bcrypt timeouts under full parallel load and passes when run alone.biome lint .: the same 6 errors as master, all in untouched files, and one warning fewer.pnpm openapi:checkandpnpm check:api:clientare clean.pnpm build:packages && next build --turbosucceeds.@metsaapp/edgeauthresolves through its compileddist/index.jsin the Node server runtime with notranspilePackagesorserverExternalPackageschange.Pins platform-kit at the COR-1076 branch commit; bump to v0.3.0 once MetsaApp/platform-kit#6 is released, before merging.
Depends on: guard COR-1074 (login, sessions), the deploy-repo guard config for this host.
Cutover (deploy and infra are applied by the stack, not this PR)
umamiclient for insights.metsa.app. Rules:/(script\.js|recorder\.js|api/(send|batch|record|heartbeat)|[pq]/[^/]+)→auth: noneauth: required,requireRoles: [umami-admin],unauthenticated: auto/apipaths as the dashboard.umami:https://insights.metsa.app/.well-known/bastion/callbackand post-logout URIhttps://insights.metsa.app/secretReftoguard-production/umami-oidcGUARD_IDENTITY=1,PLATFORM_KIT_EDGEAUTH_AUDIENCES=insights.metsa.app,GUARD_USER_ISSUER=https://auth.metsa.app,GUARD_ROLE_ADMIN=umami-adminOIDC_*and theumami-oidcsecretEnvumamiproject comment) say an Envoy SecurityPolicy gates Umami onumami-admin, but none exists. The corrected wording is in the stack's deploy notes.Generated by Claude Code