Cookies & Safari
Auth is cookie-based. The session cookie the auth Worker sets is __Secure-…; Secure; SameSite=None; Partitioned. Those attributes are correct for every HTTPS topology — but two setups still break sign-in, and both are browser/transport issues, not bugs in the cookie. Here's exactly when, and the fix.
What the attributes mean
Secure— only sent over HTTPS. (This is whyhttp://localhostcan't store it in Safari — see below.)SameSite=None— allows the cookie to ride cross-site requests, needed when your app and the auth Worker are on different sites.Partitioned(CHIPS) — opts into partitioned third-party cookies in browsers that support it (Chrome). Safari's CHIPS support is incomplete, so it doesn't rescue the cross-site case there.
Failure 1 — cross-site in production (Safari blocks it)
App on myapp.com, auth Worker on myapp-auth.workers.dev. The cookie is set by a different registrable domain than your app, so it's a third-party cookie. Safari and iOS block third-party cookies by default — sign-in looks like it works, then getMe() returns null because the cookie was never stored. Chrome currently allows it via the Partitioned attribute; Safari does not.
myapp.com → auth on auth.myapp.com. Now the cookie is same-site (first-party) and Safari stores it. This is the recommended production setup — see Custom domain for auth. The dashboard flags at-risk deployments (a real production origin with no custom domain attached).Failure 2 — http://localhost in dev (Safari won't store Secure)
Even if you make the cookie first-party with a dev proxy, it's still Secure — and Safari refuses to store a Secure cookie over http://localhost (Chrome makes a localhost exception; Safari doesn't). So local sign-in in Safari fails until you serve your dev server over HTTPS.
Fix: serve localhost over HTTPS (e.g. vite-plugin-mkcert → https://localhost:5173) and trust that origin. Full setup in Local development.
Troubleshooting matrix
| Setup | Chrome / Edge | Safari / iOS | Fix |
|---|---|---|---|
| App + auth on the same domain (custom domain), HTTPS | works | works | — (recommended) |
App on myapp.com, auth on *.workers.dev |
works (Partitioned) | blocked | Attach a custom domain on your app's domain |
Dev over http://localhost (with auth proxy) |
works | won't store Secure | Serve dev over https://localhost (mkcert) |
Dev over https://localhost (with auth proxy) |
works | works | — |
Symptom & how to confirm
The tell is always the same: sign-in returns success, but getMe() / getSession() returns null right after. Confirm it's a cookie-storage problem by checking the browser's Application → Cookies for the __Secure-…session cookie — if it's absent after a "successful" sign-in, the browser declined to store it, and you're in one of the two cases above. (If the cookie is present in the browser but null on the server, that's a different issue — you forgot to forward cookies; see SSR & cookies.)