Accounts on your server
Run accounts and sync on your own server, with your own domain.
Accounts and sync currently need a Cloudflare server with a D1
database. A native server reports accounts: false and the app hides the
account page.
Turn them on
Accounts switch on when the Worker has the GLYPH_DB database binding and
PUBLIC_ORIGIN set. glyph setup cloudflare does both. Check with:
curl https://api.example.com/v1/health # "accounts": true
Domain and passkeys
| Setting | Example | Meaning |
|---|---|---|
PUBLIC_ORIGIN | https://api.example.com | where the sign-in page is served |
ACCOUNT_RP_ID | example.com | the domain passkeys belong to |
ACCOUNT_EXTRA_ORIGINS | android:apk-key-hash:... | extra WebAuthn origins for mobile apps |
Use a subdomain for the API so the bare domain stays free for a website. Set
ACCOUNT_RP_ID to the bare domain: passkeys then work on every subdomain.
A passkey only works for the domain it was created on. Changing
ACCOUNT_RP_ID later invalidates every passkey. Users still get in with their
password, a pairing code or the recovery code, then add a new passkey. Pick the
final domain before real users sign up.
Admin access
The admin API is off until you set a password hash:
glyph hash-password # prints a hash; the password is stored nowhere
glyph cloudflare secret ADMIN_PASSWORD_HASH
glyph remote login https://api.example.com
glyph remote status
Admin logins are locked for 15 minutes after five wrong passwords and only work over HTTPS. The admin login checks Argon2id on the Worker; if the free plan's CPU limit stops it, it needs the Workers Paid plan.
Device limit
The limit is a server setting; the app only shows it.
| Command | Effect |
|---|---|
glyph remote accounts default-limit | show the default (5) |
glyph remote accounts default-limit 5 | default for every account, 1–100 |
glyph remote accounts limit alice 10 | own limit for @alice |
glyph remote accounts limit alice default | back to the default |
glyph remote accounts show alice | limit in force and devices |
Changes apply at once. Lowering a limit keeps existing devices signed in; new ones must wait until the account is below it. At the limit the sign-in page lets the user remove a device first.
Only signed-in users
glyph remote limits --require-account true
Every /v1/* route then needs a valid account token; guests get HTTP 401
account_required. Sign-in, health and public share pages stay reachable.
How sign-in works
- Handle:
@name, 3–20 charactersa-z 0-9 _, unique, changeable once per 30 days. A released handle stays blocked for 30 days. - Password: the device computes
Argon2id(password, salt); the server only stores the salt and a hash of that key. The password never reaches the server. - Passkeys: WebAuthn ES256/RS256 with user verification; only the public key is stored.
- Pairing code: a new device shows a code, a signed-in device approves it.
- Recovery code: shown once at sign-up, stored as a hash.
- Tokens: per device an access token (1 hour) and a refresh token (90 days, rotated on every use). Only hashes are stored.
- Sync: last writer wins per item; deletions are kept for 180 days.
Backups
npx wrangler d1 export glyph --remote --output backup.sql
If other people use your server, you hold their personal data. Depending on your country you may need a privacy notice and an imprint. See Privacy for what is stored.