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.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.
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’sUserDurableObject, 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.
OAuth sign-in via authentication gatekeepers
Authentication gatekeepers are gatekeeper Workers that advertiseprovidesAuth 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_GATEKEEPERSis 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
- GitHub
- Google
- Cloudflare
Create a GitHub OAuth App
Go to GitHub Settings → Developer settings → OAuth Apps and click New OAuth App.Fill in the application details:
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.- Application name: any name (e.g. “My Cloudflare OS”)
- Homepage URL: your
PUBLIC_BASE_URL - Authorization callback URL:
${PUBLIC_BASE_URL}/gatekeeper/github/oauth
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.
Set the credentials
In local dev, add to your root In production, set
.dev.vars (or to packages/gatekeeper-github/.env):CLIENT_ID and CLIENT_SECRET as secrets on the gatekeeper-github Worker.Combining multiple providers
You can list any combination of providers inAUTH_GATEKEEPERS. The order determines the order of sign-in buttons:
Cloudflare Access SSO
If your deployment is protected by Cloudflare Access, the backend automatically reads theCf-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):- The client calls
PublicApi.startGatekeeperLogin(vendorId). The backend creates a short-livedPendingLoginDurable Object, hands the gatekeeper aLoginConnectCallbackImpl, and returns the gatekeeper’s OAuth URL plus anattemptstub. - The client opens the OAuth URL in a pop-up and calls
attempt.wait(), which blocks on thePendingLoginDO. - When the gatekeeper’s OAuth pop-up completes, the gatekeeper calls
complete(user). The callback readsuser.getAuthenticatedEmail(), resolves or creates the email-keyedUserDurableObject, mints a session, and delivers the"<email>:<secret>"token to thePendingLoginDO. attempt.wait()resolves with the token. The client stores it and authenticates as usual.