Skip to content
docker · networking · auth

Supabase JWT authreverse-proxy

A thin authentication reverse-proxy built on the kbve crate's feature-gated gate module. It runs as a sidecar in front of an internal service so the upstream binds localhost and only the gate is exposed — fronting n8n, Grafana, Longhorn, ArgoCD, Forgejo, and Supabase Studio.

Validate then proxy

The gate accepts a Supabase JWT from a bearer header, an sb-access-token/kbve_gate cookie, or a query param, then applies an authz policy before forwarding to the localhost-bound upstream.

  • jwt-only — any valid Supabase JWT passes.
  • is_staff — forum.is_staff(sub) must return true.
kbve-gateApp
kbve gate moduleBuilt on
kbve/kbve-gateImage
Supabase JWTAuth

What it gives you

Features

JWT + authz policy

Validates a Supabase JWT, then enforces jwt-only or is_staff via a short-lived service_role token.

Login bounce

302s unauthed cross-subdomain navigations to the login page and sets a scoped kbve_gate cookie on return.

Sidecar or standalone

Shares a pod with an editable upstream, or runs as its own Deployment + Service + HTTPRoute for ones we don't own.

Downstream identity injection

Injects basic-auth, bearer tokens, or a trusted user header so gated tools trust the gate-authed staff user.

Fronts the toolchain

Guards n8n, Grafana, Longhorn, ArgoCD, Forgejo, and Supabase Studio behind one auth model.

Access

Auth & configuration

The gate accepts a Supabase JWT from an Authorization: Bearer header, an sb-access-token / kbve_gate cookie, or a ?access_token= query param. After the JWT validates it applies an authz policy:

  • jwt-only — any valid Supabase JWT passes.
  • is_staffforum.is_staff(sub) must return true. The gate mints a short-lived service_role JWT from SUPABASE_JWT_SECRET to call PostgREST, so the stale stored service-key is never used.
EnvDefaultPurpose
GATE_LISTEN0.0.0.0:5678bind address
GATE_UPSTREAMhttp://127.0.0.1:5679upstream base URL
GATE_UPSTREAM_PREFIXpath prefix prepended to every upstream request (Grafana sub-path)
GATE_UPSTREAM_CA_CERT_PATHCA bundle to trust an HTTPS upstream (ArgoCD TLS)
GATE_AUTHZis_staffis_staff or jwt-only
GATE_STAFF_SCHEMAforumPostgres schema holding is_staff
GATE_UPSTREAM_BASICBasic <b64> injected downstream
GATE_UPSTREAM_BEARERAuthorization: Bearer <token> injected downstream (ArgoCD apiKey)
GATE_FORWARD_USER_HEADER / GATE_FORWARD_USER_VALUEtrusted identity header injected downstream (Grafana auth-proxy)
GATE_LOGIN_REDIRECT302 target for unauthed browser navigations
GATE_COOKIE_DOMAINdomain scope for the minted session cookie (e.g. .kbve.com)
SUPABASE_JWT_SECRETrequired
SUPABASE_URLrequired for is_staff (direct PostgREST)

Cross-subdomain

Login bounce

The KBVE session lives in the browser (IndexedDB), so a cross-subdomain navigation carries no token. The gate completes auth with a bounce:

  1. Unauthed navigation to a gated host → 302 to GATE_LOGIN_REDIRECT?redirect_to=<original URL>.
  2. The login page, once a session exists, returns the browser to redirect_to?access_token=<jwt>.
  3. The gate validates the token, sets a kbve_gate cookie scoped to GATE_COOKIE_DOMAIN, and 302s to a clean URL. Subsequent requests carry the cookie.

The login page only honours redirect_to targets on *.kbve.com over https, so the token can never be handed to a foreign origin.

Consumers

Deployment shapes

Two shapes depending on whether the upstream is in the same pod:

  • Sidecar — the gate shares a pod with the upstream, which binds 127.0.0.1. Used when the workload is ours to edit (n8n).
  • Standalone — the gate is its own Deployment + Service + HTTPRoute and proxies a separate in-cluster Service. Used for Helm- or operator-managed upstreams we don’t own (Grafana, Longhorn, ArgoCD).

The first consumer fronts n8n: n8n moves to 127.0.0.1:5681, the gate owns the Service port 5678, and n8n.kbve.com routes through it so the panel stays staff-only.

grafana.kbve.com → standalone gate in monitoringmonitoring-grafana:80. GATE_UPSTREAM_PREFIX=/dashboard/grafana/proxy matches Grafana’s sub-path root_url. Grafana’s own login is bypassed with its auth-proxy: GATE_FORWARD_USER_HEADER=X-WEBAUTH-USER / GATE_FORWARD_USER_VALUE=kbve-staff, so the gate-authed staff user is trusted downstream.

longhorn.kbve.com → standalone gate in longhorn-systemlonghorn-frontend:80. No prefix (the UI roots at /) and no upstream login — the gate’s is_staff is the only auth in front of the panel.

argo.kbve.com → standalone gate in argocdargocd-server:443 over HTTPS (GATE_UPSTREAM_CA_CERT_PATH trusts the argocd-server-tls CA). ArgoCD keeps its own login, so the gate injects an admin apiKey as GATE_UPSTREAM_BEARER (synced by ESO from the argocd-auth secret) on every request — the SPA then authenticates as that account instead of redirecting to ArgoCD’s login.

forgejo.kbve.com → standalone gate in forgejoforgejo-http:3000. The gate enforces is_staff authz while API and git operations (e.g., /api/, /v2/, /KBVE/) bypass the gate for token-based auth. Forgejo is configured with OAuth/OIDC to use Supabase as the identity provider, enabling automatic account creation and login for authenticated staff users.

Questions

Frequently asked

What is KBVE Gate?

KBVE Gate is a thin authentication reverse-proxy built on the kbve crate's feature-gated gate module. It runs as a sidecar in front of an internal service so the upstream binds localhost and only the gate is exposed, fronting tools like n8n, Grafana, Longhorn, ArgoCD, Forgejo, and Supabase Studio.

How does KBVE Gate authenticate requests?

The gate accepts a Supabase JWT from an Authorization Bearer header, an sb-access-token or kbve_gate cookie, or an access_token query param. After the JWT validates it applies an authz policy — jwt-only lets any valid JWT pass, while is_staff requires forum.is_staff(sub) to return true.

How does KBVE Gate handle cross-subdomain login?

Because the KBVE session lives in the browser's IndexedDB, a cross-subdomain navigation carries no token, so the gate does a login bounce — it 302s unauthed navigations to GATE_LOGIN_REDIRECT, the login page returns with access_token, and the gate validates it and sets a kbve_gate cookie scoped to GATE_COOKIE_DOMAIN.