Sessions without a session store
Authentication here is deliberately boring. Boring is the point: every exotic mechanism is one more thing to get subtly wrong.
Hashing
Passwords are stretched with PBKDF2-SHA256 at 100,000 iterations using a 16-byte random salt and a 32-byte derived key. The stored value is self-describing, so the iteration count can be raised later without breaking existing rows:
pbkdf2$100000$<saltBase64>$<hashBase64>
Verification re-derives the key with the parameters recorded in the stored string and compares the result in constant time. WebCrypto is available in the Workers runtime, so there is no dependency to audit.
Tokens
A session token is two concatenated crypto.randomUUID() values — 256 bits of entropy from the platform CSPRNG. It is opaque: it carries no claims, so there is nothing to forge and nothing to decode. The server looks the token up, joins it to its user, and checks expires_at.
The cookie
The token travels in a cookie with four flags that matter:
HttpOnly— script on the page cannot read itSecure— it never crosses a plaintext connectionSameSite=Lax— cross-site form posts will not carry itMax-Age— it expires, in the browser and in the database
Signing out deletes the row and clears the cookie. Deleting the row is the part that actually matters: a token with no row behind it is just a string.