RFC: Cloudflare Access for Admin GUI

Date: 2026-04-15

Background

The admin GUI is deployed as static assets to Cloudflare Pages. Anyone who knows or guesses the URL can currently download the JS bundle, inspect the routes and component tree, and enumerate the API surface the admin app talks to. Authentication on the admin app itself (login screen, AX session cookie) gates what the API returns, but does nothing to gate who can see the frontend code.

We would like to restrict both: only authenticated staff should be able to load the admin GUI bundle at all.

Proposal

Put the admin GUI Pages deployment behind Cloudflare Access (Cloudflare Zero Trust). Every HTTP request for the admin app HTML, JS bundles, static assets, API calls that go through the same hostname is intercepted by Cloudflare and requires a valid identity proof before any bytes reach the client.

Identity is proven via SSO (Google / Okta / email OTP, configured per organization). On success, Cloudflare issues a short-lived JWT that is attached to every subsequent request as:

Avoiding double-login

The admin GUI today has its own login screen that authenticates against api-gateway and produces an AX session cookie. Stacking Cloudflare Access in front of that means staff would log in twice once for Access, once for the admin app. That's silly.

Instead, wire Access as the identity source and let the admin app mint its AX session from the Access JWT:

  1. api-gateway verifies the Cf-Access-Jwt-Assertion header on an SSO endpoint (e.g. POST /api/access-sso). Verification checks:
    • Signature against Cloudflare's JWKS at https://<team>.cloudflareaccess.com/cdn-cgi/access/certs
    • aud claim matches the application's Access AUD tag
    • exp not in the past
    • extract the verified email claim
  2. If the email matches an AX staff user, issue the usual AX session token and set the ax_token cookie. If not, reject.
  3. The admin GUI, at boot, calls /api/access-sso to exchange the Access JWT for an AX session before doing anything else. If the call succeeds, skip the admin login screen entirely. If it fails (misconfiguration, unknown email), fall back to the existing login flow.

Cloudflare silently renews the Access JWT as long as the SSO session is alive, so the AX session refresh flow doesn't need to change.

Security considerations

Open questions