refactor: relay-only BFF — remove the in-app identity layer (ADR 0014) - #29
Merged
Conversation
The BFF is now a pure token relay in every deployment: it reads the bearer injected by a fronting auth proxy (x-forwarded-access-token) or an explicit Authorization: Bearer, forwards it to the gateway, and does nothing else with it. Browser authentication — login, cookie sessions, refresh, logout, CSRF — is owned by the auth proxy (oauth2-proxy standalone, kube-auth-proxy federated), which is how every production deployment already ran. Removed: - Standalone OIDC custodian: oidc_handler.go, auth/session.go (AES-256-GCM cookie codec), session_manager.go (transparent refresh), CSRF middleware, and the /auth/discovery, /auth/token-exchange, /auth/session, /auth/logout endpoints (+ all their tests) - Frontend PKCE flow: oidc.ts, AuthCallbackPage, useSession probe; the login page is now dev-mode only - CORS allowlist machinery and ALLOWED_ORIGINS — the BFF is same-origin behind its proxy; the one remaining browser check is same-origin enforcement on the terminal WebSocket handshake (one implementation, down from three divergent ones) - Mode detection: OIDC_ISSUER/OIDC_CLIENT_ID/OIDC_CLIENT_SECRET/ OIDC_SCOPES/OIDC_USER_ROLE/SESSION_SECRET/DEPLOYMENT_CONTEXT env vars and the TrustProxyHeader gate; AUTH_DISABLED is the only switch left - Dead extension surface: workspaceBinding slot, workspaceBinding/ resourceLinks feature flags, SandboxPolicyTab.tsx Fixed along the way: - Dev-mode whoami now returns the configured ADMIN_ROLE instead of hardcoded role names that never matched it (admin pages were silently inaccessible in dev) - 401 handling outside dev mode reloads the page (once) so the proxy can re-authenticate, instead of redirecting to a /login route that doesn't exist in proxied deployments - logout drops the double fallback and goes straight to LOGOUT_URL - dev-env.sh: gateway allows unauthenticated calls locally so make dev-full works with the auth-disabled BFF; Keycloak still mints real JWTs for exercising the Bearer relay path Net: -2,000 lines. go build/vet/test, tsc, jest (168), eslint, prettier, webpack prod build all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gkrumbach07
added a commit
that referenced
this pull request
Aug 7, 2026
The BFF never terminates authentication — a fronting auth proxy (oauth2-proxy standalone, kube-auth-proxy federated) owns login, sessions, refresh, and CSRF in every authenticated deployment. Implementation in PR #29 (-2,000 lines). - ADR 0014 (new): relay-only decision; supersedes ADR 0010. Standalone and federated become the same architecture with different proxy operators; documents the proxy-is-the-only-path deployment invariant - ADR 0010: marked Superseded — its requirements were right, oauth2-proxy meets them on the other side of a network boundary - ADR 0001 v3: pattern space collapses to token relay; the only auth switch left is AUTH_DISABLED - ADR 0003 v3: 'the BFF is a token relay' — the dumb-pipe doctrine is true again, with the drift history recorded - ADR 0011 v2: three jobs (custody removed); never-list gains 'no auth termination' - ADR 0005/0008/0012: consistency edits (embedding mechanism = dedicated proxy flow; WS upgrade auth via proxy; dead flags/slot removed in #29) CLAUDE.md and .claude rules updated to relay-only reality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 tasks
Its only callers were the deleted auth endpoints. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Config validated live on the ROSA cluster (Dex IdP, gateway audience = client_id): ID-token passthrough, WebSocket upgrades, and the unverified-email flag Dex's OpenShift connector requires. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gkrumbach07
added a commit
that referenced
this pull request
Aug 8, 2026
- CLAUDE.md: remove phantom "oidc/ subdir" from project structure - CONTRIBUTING.md: lint is golangci-lint not go vet - CONTRIBUTING.md: ADR 0007 reference → .claude/rules/openshell-api.md - security.md: remove CORS claim (no CORS middleware exists) - bff-go.md: remove ALLOWED_ORIGINS (removed in PR #29) - FEATURE_FLAGS.md: remove stale implementation TODOs (all done) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This was referenced Aug 8, 2026
gmenher
added a commit
to gmenher/openshell-dashboard
that referenced
this pull request
Aug 9, 2026
1. gRPC error extraction: Replace fragile sanitizeGrpcMessage (regex +
colon-splitting heuristic) with errors.As + GRPCStatus() interface.
Extracts the original clean gateway message directly, bypassing
status.FromError's message replacement in grpc-go v1.82+.
2. Add test coverage: TestWriteGrpcErrorWrapped verifies that short
messages ('not found', 'denied') and wrapped errors are extracted
cleanly regardless of wrapper context.
3. About modal: Use isAutoFit with autoFitMinModifier for responsive
layout without mid-word wrapping.
Note: CORS/ALLOWED_ORIGINS change dropped per PR Gkrumbach07#29 which removed
the in-app identity layer entirely.
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.
Summary
Implements the shape A / relay-only decision (ADR 0002 (relay-only auth), on the
docs/adrsbranch → PR #17): the BFF is a pure token relay in every deployment. Browser authentication — login, cookie sessions, refresh, logout, CSRF — belongs to the auth proxy in front of the BFF (oauth2-proxy standalone, kube-auth-proxy federated), which is how every production deployment already ran. The secure-agent-workspace validated pattern deploys this dashboard behind oauth2-proxy today and never used the built-in custodian.Net: −2,000 lines. One auth pattern, one trust story: the thing in front of me authenticated this request.
Removed
oidc_handler.go,auth/session.go(AES-256-GCM cookie codec),session_manager.go(transparent refresh), CSRF middleware, and the/auth/discovery,/auth/token-exchange,/auth/session,/auth/logoutendpoints + testsoidc.ts,AuthCallbackPage,useSessionprobe; login page is dev-mode onlyALLOWED_ORIGINS— same-origin-only behind the proxy; the three divergent origin checks collapse to one (same-origin enforcement on the terminal WS handshake)OIDC_ISSUER/CLIENT_ID/CLIENT_SECRET/SCOPES/USER_ROLE,SESSION_SECRET,DEPLOYMENT_CONTEXT,TrustProxyHeader.AUTH_DISABLEDis the only switch left — this also removes the FE/BE mode-detection mismatch class entirelyworkspaceBindingslot,workspaceBinding/resourceLinksfeature flags,SandboxPolicyTab.tsxFixed
whoamireturns the configuredADMIN_ROLEinstead of hardcoded role names that never matched it (admin pages were silently inaccessible in dev)/loginroute that doesn't exist in proxied deploymentsLOGOUT_URL(default/oauth2/sign_out), no double fallbackmake dev-full: the local gateway allows unauthenticated calls so the auth-disabled BFF works against it; Keycloak still mints real JWTs for exercising the Bearer relay path with curl/CLIDeployment requirement (documented in README)
Unconditional trust in
x-forwarded-access-tokenis safe only when the proxy is the sole network path to the BFF (sidecar, pod-internal port, proxy-only ingress) — the standard contract for everyx-forwarded-*consumer.Relationship to other PRs
Test plan
go build ./... && go vet ./... && go test ./...— all greentsc --noEmit, jest (168/168), eslint, prettier — all greenmake dev-full→ Continue as developer → workspaces/sandboxes/terminalpr-29; terminal WS pending a browser check)🤖 Generated with Claude Code