Adds internal/web/oidc.DexAuth, the production web.Auth impl behind the seam
(ADR-011, docs/ui-spec.md §6). Standard Authorization Code flow against Dex:
- Routes() mounts /auth/login (state+nonce, redirect to authorize),
/auth/callback (code exchange, ID-token verify, nonce check, allowlist:
sub must equal Config.AllowedSubject else 403, set session, redirect /),
/auth/logout (clear session).
- Middleware redirects unauthenticated requests to /auth/login, slides the
session expiry on each authenticated request; /healthz and /auth/* bypass.
- CurrentUser resolves the principal from the session cookie.
- Sessions: server-side in-memory store (single Stage-0 replica) keyed by an
HMAC-SHA256 (HS256) signed, HttpOnly, Secure, SameSite=Lax cookie with a
short TTL + sliding refresh. State->nonce pending map is one-time + expiring
(replay/CSRF defense). Tokens are never logged.
Constructor New(ctx, Config, ...Option); the six-field Config (Issuer,
ClientID, ClientSecret, RedirectURL, SessionSecret, AllowedSubject) is what
cmd/tapir wires from TAPIR_OIDC_*/TAPIR_DEX_*/TAPIR_SESSION_SECRET/
TAPIR_ALLOWED_SUBJECT. Options (clock, TTL, insecure cookies) are test-only.
Tests use a fake OIDC issuer via httptest (discovery + JWKS + token endpoint
signing an RS256 ID token) — no live Dex: login 302s to authorize; callback
for the allowlisted sub sets a session and 302s to /; non-allowlisted sub 403;
middleware redirects unauthenticated and passes authenticated; logout clears;
plus expiry, tampered-cookie, and unknown-state cases.
Deps (per ADR-006 / ui-spec §6): adds github.com/coreos/go-oidc/v3 — the
homelab-standard OIDC lib, small, handles discovery + JWKS + ID-token
verification; pairs with the already-present golang.org/x/oauth2. go-jose/v4
(transitive via go-oidc) is used directly only in tests to sign the fake
issuer's tokens.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lets the Dex session layer (lane B) and page handlers (lane C) build independently:
handlers depend only on web.Auth; oidc.DexAuth (B) and StubAuth (dev) implement it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>