Authentication on Cloudflare Workers is mostly the same as anywhere — until you hit the edge-specific gotchas: where sessions live, a cookie trap that silently breaks Safari, a CPU budget that won't run a normal password hash, and OAuth callbacks that have to point at exactly the right URL. This guide covers each, the standard fixes, and where Flarelink does it for you.
Use a library like BetterAuth or Lucia directly on a Worker, wire up D1/KV yourself. Maximum control; you own every gotcha below.
Clerk, Auth0, WorkOS — call a third-party service from your Worker. Fast, but your users live on their infrastructure and pricing is per-MAU.
Flarelink deploys a source-available auth Worker to your Cloudflare account with the gotchas handled. No per-MAU fee; you own the users.
All three are legitimate. If you enjoy owning the details, rolling your own is very doable — the rest of this guide is the map. If you'd rather skip to a working setup, that's what Flarelink is.
Every authenticated request checks the session. If sessions live in D1, that's a row read on the hot path of every request — and D1 bills per row read. Cloudflare KV is purpose-built for this: globally cached, sub-millisecond reads, negligible cost.
The trade-off is consistency: KV is eventually consistent, so a sign-out or revocation propagates within KV's window (seconds) rather than instantly at every edge. For session tokens that's almost always the right call; just don't assume global revocation is synchronous.
Flarelink stores sessions in KV by default. More on the consistency window in Limits & semantics.
The default Workers setup puts your app on one domain and the auth Worker on *.workers.dev — a different registrable domain. The session cookie is then a third-party cookie (SameSite=None; Secure; Partitioned), and Safari and iOS block third-party cookies. Sign-in looks like it works, then the session check returns null because the cookie was never stored. Chrome currently allows it via the Partitioned (CHIPS) attribute; Safari doesn't.
The fix: put the auth Worker on a subdomain of your app's own domain (app on myapp.com → auth on auth.myapp.com), which makes the cookie same-site. There's a second, dev-only variant: Safari also refuses to store a Secure cookie over http://localhost, so serve local dev over HTTPS.
Full breakdown + a per-browser matrix: Cookies & Safari. Flarelink ships a one-click custom-domain attach and flags at-risk deployments.
The Workers free plan caps CPU at ~10 ms per request. A properly tuned scrypt or a 600k-iteration PBKDF2 (the OWASP baseline) blows straight past that, so naive auth code either errors or you're tempted to under-hash silently.
The honest approach: use PBKDF2-SHA256, pick an iteration count you can defend, publish it, and raise it on the paid plan. Store the count with each hash so you can rehash-on-login as you increase it — no bulk migration, no forced reset.
Flarelink uses PBKDF2-SHA256 with a per-deployment count (100k default, 600k on the Workers paid plan), rehash-on-login, and publishes the exact parameters on the trust page.
OAuth providers redirect back to a single, exact callback URL. On Workers that URL is on your auth Worker's host — and if you later move the Worker to a custom domain, the callback URL changes and every provider needs updating, or sign-in fails with redirect_uri_mismatch. The host, scheme, and path must match character-for-character.
Get the redirect URI from one source of truth and paste it verbatim. Keep dev and prod hosts as separate OAuth apps so their callbacks don't collide.
Step-by-step Google + GitHub setup with the exact URIs: OAuth provider setup.
Two things bite locally: the same cross-site cookie problem (your local app on localhost:5173, the auth Worker on workers.dev), and Safari refusing Secure cookies over plain http://localhost. Reverse-proxy /api/auth/* through your dev server to make the cookie first-party, and serve dev over HTTPS (e.g. vite-plugin-mkcert). Add every local origin to your trusted-origins list.
The full local setup: Local development.
Flarelink provisions an auth Worker to your Cloudflare account with every gotcha above handled — sessions in KV, the right cookie attributes, defensible hashing, OAuth wiring, and a local-dev story. The difference from hosted auth is that the Worker runs on your account, the users live in your D1, and the Worker is source-available — you can rebuild it from source and diff it against what's deployed.
Start with the quickstart, or read why database + storage are server-first by design. Prefer to verify before trusting? The trust page shows how.
Free during beta. A working, verifiable auth Worker on your own account in about a minute.