Create and replace the first administrator
Dee Wan has no public registration. A fresh installation has no account until someone consumes its one-time claim link. The installer binds that link to one normalized BOOTSTRAP_ADMIN_EMAIL. The claim page never accepts a different address.
Configure the methods before deployment
Section titled “Configure the methods before deployment”BETTER_AUTH_SECRET is required and is generated by the installer. Put provider credentials in Worker secrets, never in vars. Put the non-secret settings in backend/wrangler.jsonc.
| Method | Required configuration |
|---|---|
| Password | BETTER_AUTH_SECRET |
| Magic link | BETTER_AUTH_SECRET, secret RESEND_API_KEY, and var MAIL_FROM |
BETTER_AUTH_SECRET, var GOOGLE_CLIENT_ID, and secret GOOGLE_CLIENT_SECRET |
|
| GitHub | BETTER_AUTH_SECRET, var GITHUB_CLIENT_ID, and secret GITHUB_CLIENT_SECRET |
| Passkey | BETTER_AUTH_SECRET and a valid BACKEND_URL (plus FRONTEND_URL when the admin UI has its own origin). It cannot claim the installation. |
On an unclaimed installation, AUTH_INITIAL_METHODS is a comma-separated list such as "password,magic_link,google,github". If it is absent, password is the only initial method. A listed method is still unavailable when one of its required bindings is missing. passkey is accepted only beside a method that can claim the installation: a passkey is added under Account security after the first sign-in.
After the first administrator exists, a superadmin can change the registry on the Installation page, under Sign-in methods. Installation is in the sidebar for superadmins only. The API refuses to enable an unconfigured method or leave every active superadmin without a usable method.
Claim the installation
Section titled “Claim the installation”Open the installer claim link and choose an available method:
- Password sets a 12–128 character password on the bound address.
- Magic link sends only to the bound address. There is no email field on the claim page.
- Google must return that exact verified email.
- GitHub must return that exact primary, verified email.
The email domain does not have to match the provider’s brand. For example, GitHub sign-in may prove an address ending in @google.com. Only an exact match between the normalized email addresses matters.
The claim and any verification challenge are single-use and expire no later than 15 minutes after the original claim was minted. Password, magic-link, Google and GitHub sign-in never create an account. A verified provider with an unknown email is refused. Only a site’s Cloudflare Access rule can admit a new person at sign-in (see Sign in through Cloudflare Access).
If the unclaimed link is lost or expires, mint a replacement for the configured address:
Without --bootstrap, the command resets the password in an emergency for the sole active superadmin. It does not create the first account. See Password ownership and recovery.
One account, several methods
Section titled “One account, several methods”Provider callbacks cannot change the account’s canonical email. The signed-in owner can change it through Account security after verifying the new mailbox. A verified Google or GitHub identity with the same normalized email links to the existing account instead of creating another one. GitHub requires the matching address to be primary as well as verified. Provider access, refresh and ID tokens are not retained.
When you first claim the installation with a password, a later magic-link sign-in keeps that original setup password. You can continue to use either method without setting the password again.
Replace a superadmin
Section titled “Replace a superadmin”Do not edit the old account’s email. Use this sequence:
- In Settings → People, under Add person, enter the replacement email, pick a role and use Add.
- The address already has an account: it gets the role at once. If its row says it cannot sign in yet, use Create link and send that password link privately. A matching verified Google or GitHub identity can also link on sign-in.
- No account yet: no account is created. An invitation is made instead (see Add a person). The replacement opens the invitation link, types the address it was sent to, enters the emailed code when mail is configured, and chooses a password. Only then does the account exist.
- Confirm the replacement is in the People list and its row says Can sign in (or Cloudflare Access where Access is set up). A pending invitation is not an account and cannot be promoted.
- On that People row, use the shield button (Make … a superadmin) and confirm Make superadmin. An account with no usable sign-in method is refused. Existing sessions for the promoted account are revoked.
- Sign in as the replacement account. Confirm Installation is in its sidebar.
- On the Installation page, under Superadmins, deactivate the old account.
Deactivation signs the old account out and preserves content and historical references. Reactivation requires a fresh sign-in. The API refuses self-deactivation and any change that would remove the last active, usable superadmin.
Account security
Section titled “Account security”Every signed-in user can open Account security from their identity menu (/account/security),
including users without a site grant. It covers your own account only: admin language, linked
Google and GitHub connections, and your passkeys. Password setup, magic-link configuration and the
deployment-wide sign-in methods are not on this screen.
Keep a second way to sign in, or a second superadmin who can sign in, before you remove your last method. For lost devices, forgotten passwords and a locked-out superadmin, see Password ownership and recovery.
Admin language
Section titled “Admin language”Under Language, pick English, ไทย, Русский, Español, Français or Deutsch. Same as browser follows your browser language and falls back to English. The choice is saved in your account and applies on every site and device. It changes only the admin interface, dates and numbers. It never changes a site’s content Languages, which stay under Settings → Languages. Screens not translated yet stay in English.
Disconnect a sign-in provider
Section titled “Disconnect a sign-in provider”Account security lists your Google and GitHub connections. A connection can remain linked even when sign-in through that provider is unavailable.
Choose Unlink, review the provider name and session warning, then confirm. The server removes that exact connection and revokes every CMS session for your account, including the current session, in one atomic operation. You must sign in again. No provider tokens or provider identity ids are returned by this screen or its API. Passwords and pending verification links are not removed.
An ordinary user may remove their last provider. A superadmin may also remove their last personal method if another active superadmin can still sign in. The server refuses any unlink that would leave the deployment with no active superadmin able to use an enabled, configured method. A configured method without a usable account link does not count. When magic-link sign-in is configured and enabled, it uses the user’s email. A refusal preserves the connection and all sessions.
Unlinking disconnects the CMS account. It does not revoke the OAuth application’s authorization at Google or GitHub. A later permitted sign-in with the same verified email can link the provider again through the existing sign-in flow. There is no provider-link button on Account security.
Passkeys
Section titled “Passkeys”Passkeys are off until a superadmin switches them on (see Passkeys). Then each person adds their own under Account security, after signing in another way within the last 24 hours. Sign in with a passkey asks for no address. You can rename and remove your own passkeys. The last way you can sign in cannot be removed. Removing a passkey keeps current sessions. A deactivated account cannot sign in with a passkey.
To check real email delivery, provider callbacks and passkeys on a real deployment, follow authentication acceptance. Local checks do not prove them.
Next step
Section titled “Next step”Take your first site to published content.
Unreleased / pre-MVP; no stable version
Source revision: fe23db481c422b40e317b92fc98116b4c0c26a87 (modified checkout)
Build date (UTC): 2026-10-18T09:22:34.630Z
Upgrade target: unavailable: modified checkout. Release notes