From c9863e96332e28a22b48d7c4590a515006392c88 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 3 Jun 2026 08:53:06 +0200 Subject: [PATCH] feat(oidc): echo caller subject in the 403 to bootstrap the allowlist First-login chicken-egg: TAPIR_ALLOWED_SUBJECT can't be known until the user logs in once, but the allowlist gates login. Echo the (non-secret, opaque) subject in the forbidden response so the maintainer can read it in the browser, set the 1P item, and lock the allowlist. --- internal/web/oidc/oidc.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/web/oidc/oidc.go b/internal/web/oidc/oidc.go index 591b980..ba11f2b 100644 --- a/internal/web/oidc/oidc.go +++ b/internal/web/oidc/oidc.go @@ -242,9 +242,11 @@ func (d *DexAuth) handleCallback(w http.ResponseWriter, r *http.Request) { return } - // Single-user authz: only the allowlisted subject may sign in. + // Single-user authz: only the allowlisted subject may sign in. On mismatch + // we echo the caller's own subject (an opaque id, not a secret) so the + // maintainer can bootstrap TAPIR_ALLOWED_SUBJECT on first login. if idToken.Subject != d.cfg.AllowedSubject { - http.Error(w, "forbidden", http.StatusForbidden) + http.Error(w, "forbidden — not the allowlisted subject. your subject is: "+idToken.Subject, http.StatusForbidden) return }