CybersecurityOctober 01, 2026•6 min read

Building Dual-Layer Admin Auth on Cloudflare D1

PBKDF2 password hashing with Web Crypto, opaque session tokens, and a security boundary you can read in one afternoon.

IE
Intactic Engineering Team
Platform Engineering
Building Dual-Layer Admin Auth on Cloudflare D1

When we left Supabase Auth behind, we had to rebuild CMS authentication from primitives — and it turned into the most greppable auth system we have ever owned. Here is the complete design: PBKDF2 hashing, hashed opaque tokens, a seven-day httpOnly cookie, and two independent enforcement layers.

Retiring Supabase meant retiring Supabase Auth, which forced a question every platform team eventually faces: what does authentication look like when you own every primitive? For our CMS — a privileged /admin surface with a handful of trusted operators — the answer was a D1-backed session system built entirely on Web Crypto. This post documents the design exactly as it ships.

The threat model comes first. The admin panel manages published content, media uploads, and form submissions for a corporate site. There are few users, all trusted; the risks that matter are credential theft, session theft, and authorization gaps between the UI and the API. That ordering shaped every decision: prioritize hash strength and token entropy over exotic features, and make the enforcement boundary impossible to bypass by accident.

Password storage uses PBKDF2-SHA256 with 100,000 iterations, implemented with crypto.subtle — the exact same code runs in the Cloudflare Workers runtime and under Node during development, which removes an entire class of environment drift. The stored format is self-describing: iterations, base64 salt, and base64 hash in a single string, so iteration counts can be raised later without a breaking migration.

Sessions are opaque 256-bit random tokens. The raw token lives only in an httpOnly cookie scoped for seven days; the database stores exclusively its SHA-256 hash. A database leak therefore reveals nothing usable — an attacker with every row in admin_sessions still cannot reconstruct a valid cookie. Logout deletes the row, which instantly invalidates the token everywhere.

Enforcement is dual-layer by design, and the two layers are independent. The admin layout is a server component gate: it reads the request path and checks the D1 session before rendering any admin page, redirecting to the login route otherwise. Separately, every API route handler under /api/admin calls verifyAdmin() before touching data and returns 401 without a valid session. The layers do not trust each other, so a future refactor that weakens one cannot silently disable both.

A subtle performance decision sits underneath: the request proxy applies security headers and path propagation but performs no per-request auth lookup. The old architecture paid one database subrequest per page view just to refresh sessions; the new one pays zero, because pages enforce at the layout and APIs enforce at the handler. Authorization still happens on every privileged request — just exactly once, and exactly where it is needed.

The lesson we keep from this build: owning your auth is viable when the system stays simple enough to audit. Two tables, two enforcement layers, standard primitives, and a boundary you can read in an afternoon. That is the whole system — and for a CMS with a handful of trusted operators, simple is not a compromise. Simple is the security feature.

Topics:#Security#Authentication#PBKDF2#Web Crypto#Sessions#Cloudflare D1
IE

Authored by Intactic Engineering Team

Platform Engineering

Senior engineering leader at Intactic specializing in high-performance cloud architectures, enterprise AI integration, and mission-critical systems.

Related Architecture Teardowns

More strategic insights from our engineering editorial team.