Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/cloudflare-os/llms.txt

Use this file to discover all available pages before exploring further.

Cloudflare OS supports three sign-in mechanisms: built-in username/password accounts, OAuth sign-in via authentication gatekeepers (GitHub, Google, Cloudflare), and Cloudflare Access SSO. These are additive — you can enable any combination, and the login page displays options for all configured methods simultaneously.

Username/password login

Username/password login is enabled by default. Users create an account with a username and password, and the account is stored in the user’s UserDurableObject, keyed by username. No external services are required. To disable the username/password form and require OAuth sign-in instead, set DISABLE_PASSWORD_AUTH=true in your environment. This variable is silently ignored if AUTH_GATEKEEPERS is empty, which prevents accidentally locking everyone out.
Always configure and test at least one OAuth gatekeeper before setting DISABLE_PASSWORD_AUTH=true. If you disable password auth without a working gatekeeper in AUTH_GATEKEEPERS, no one — including admins — will be able to sign in.

OAuth sign-in via authentication gatekeepers

Authentication gatekeepers are gatekeeper Workers that advertise providesAuth and can return a provider-verified email. Each auth-capable gatekeeper (GitHub, Google, Cloudflare) uses a single OAuth app for both sign-in and, later, connecting its full capabilities — so you only need one OAuth app per provider. How it works:
  • AUTH_GATEKEEPERS is a comma-separated allowlist of vendor IDs (e.g. cloudflare,google,github). For each listed vendor, a “Continue with …” button appears on the login page alongside the username/password form. The order of entries determines button order.
  • The primary account key is always the user’s verified email. Signing in with any allowlisted gatekeeper that yields the same verified email maps to the same UserDurableObject — the same account regardless of which provider was used.
  • Sign-in requests only the minimal scopes needed to read the verified email. The sign-in grant is transient — it self-destructs after the email is read, so signing in never leaves a persisted broad authorization. Full scopes (repo access, Gmail, AI Gateway billing) are only requested later, when the user explicitly connects the gatekeeper.

Setting up OAuth providers

1

Create a GitHub OAuth App

Go to GitHub Settings → Developer settings → OAuth Apps and click New OAuth App.
Use a GitHub OAuth App, not a GitHub App. Only OAuth Apps honor the scope parameter, which is what enables minimal-scope sign-in. A GitHub App (client ID starting with Iv…) ignores scope and will fail the email lookup unless separately configured.
Fill in the application details:
  • Application name: any name (e.g. “My Cloudflare OS”)
  • Homepage URL: your PUBLIC_BASE_URL
  • Authorization callback URL: ${PUBLIC_BASE_URL}/gatekeeper/github/oauth
2

Generate a client secret

On the app’s settings page, click Generate a new client secret. Copy the Client ID and the generated Client secret.
3

Set the credentials

In local dev, add to your root .dev.vars (or to packages/gatekeeper-github/.env):
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret
In production, set CLIENT_ID and CLIENT_SECRET as secrets on the gatekeeper-github Worker.
4

Enable GitHub sign-in

Add github to AUTH_GATEKEEPERS in your environment:
AUTH_GATEKEEPERS=github
Restart the server. A “Continue with GitHub” button will appear on the login page.

Combining multiple providers

You can list any combination of providers in AUTH_GATEKEEPERS. The order determines the order of sign-in buttons:
AUTH_GATEKEEPERS=cloudflare,google,github
Because identity is keyed by verified email, a user who signed up with GitHub and later signs in with Google will land in the same account — as long as both providers report the same verified email address.

Cloudflare Access SSO

If your deployment is protected by Cloudflare Access, the backend automatically reads the Cf-Access-Jwt-Assertion header on incoming requests and authenticates the user from the validated JWT (authenticateFromCfAccess()). No additional configuration is needed beyond setting up Access itself. Access-authenticated users are keyed by their Access-verified email, the same scheme as OAuth gatekeeper sign-in — so a user can have one account whether they arrive via Access, via a gatekeeper, or via username/password, as long as the email matches.

Sign-in flow summary

For reference, here is what happens under the hood when a user clicks “Continue with GitHub” (or any other OAuth provider):
  1. The client calls PublicApi.startGatekeeperLogin(vendorId). The backend creates a short-lived PendingLogin Durable Object, hands the gatekeeper a LoginConnectCallbackImpl, and returns the gatekeeper’s OAuth URL plus an attempt stub.
  2. The client opens the OAuth URL in a pop-up and calls attempt.wait(), which blocks on the PendingLogin DO.
  3. When the gatekeeper’s OAuth pop-up completes, the gatekeeper calls complete(user). The callback reads user.getAuthenticatedEmail(), resolves or creates the email-keyed UserDurableObject, mints a session, and delivers the "<email>:<secret>" token to the PendingLogin DO.
  4. attempt.wait() resolves with the token. The client stores it and authenticates as usual.
The minimal-scope grant used during step 3 is discarded immediately after the email is read — it is never persisted. To use a gatekeeper’s full capabilities (repo access, Gmail, AI Gateway billing), the user explicitly connects it afterward via the Connections UI, which requests the full scopes and persists the connection.

Build docs developers (and LLMs) love