Architecture

How auth runs at the edge.

No origin. No cold starts. No infrastructure to manage. Everything binds to a single Cloudflare Worker.

The stack in 60 seconds


        ┌──────────────────────────────┐
        │   User's browser / app SDK   │
        └──────────────┬───────────────┘
                       │ HTTPS
                       ▼
   ┌───────────────────────────────────────────┐
   │  auth.kynetra.dev   (Cloudflare Pages)    │
   │  Next.js 15 — marketing, dashboard, docs  │
   └──────────────┬────────────────────────────┘
                  │ fetch()
                  ▼
   ┌───────────────────────────────────────────┐
   │  kynetra-auth-api   (Cloudflare Worker)   │
   │  Hono framework + WebCrypto + jose        │
   ├───────────────────────────────────────────┤
   │  Bindings:                                │
   │    DB              → D1 (SQLite, APAC)    │
   │    RATE_LIMIT      → KV namespace         │
   │    ASSETS          → R2 bucket            │
   │    AI              → Workers AI           │
   │    AUTH_EVENTS_QUEUE → Queues             │
   │    ANALYTICS       → Analytics Engine     │
   │    + cron triggers (every 15 min, daily)  │
   └───────────────────────────────────────────┘

Why edge auth matters

Sub-millisecond JWT verification

Cloudflare's edge runs at 300+ PoPs globally. A JWT verification that takes 8-15ms on a centralized server takes <1ms on a Worker because the runtime is already warm and physically near the user.

Zero cold starts

Workers V8 isolates start in <5ms. Compare to AWS Lambda's 200-1000ms cold start for Node, or even longer for containers. Your auth flow is never the slow path.

No infrastructure to manage

No EC2, no RDS, no Redis clusters, no Kubernetes. The Worker scales from zero to millions of requests automatically. D1 is replicated across regions. Cron triggers run on Cloudflare's schedulers.

Data model

D1 SQLite schema, 9 tables. Postgres types mapped to SQLite primitives:

PostgresD1 / SQLiteStrategy
uuidtextcrypto.randomUUID() in application code
jsonbtextJSON.parse / JSON.stringify on read/write
timestampintegerUnix epoch ms — orderable, no parsing
booleaninteger (0/1)Drizzle ORM handles transparently

Tables: tenants, users, credentials, sessions, roles, memberships, audit_logs, admin_settings, mfa_enrollments.

Cryptography choices

Password hashing: PBKDF2-SHA256 @ 100k

Workers caps PBKDF2 at 100,000 iterations (vs 600k+ on Node). Combined with a 16-byte random salt this gives reasonable protection. For Argon2-grade hashing, run signup through a separate hashing service.

JWT: HS256 via jose

Symmetric HMAC. Fast at the edge, works without JWKS rotation. RS256 supported when JWKS_PRIVATE_KEY is provisioned. All tokens carry sub, tid, email, roles[], scope[], jti, iat, exp.

TOTP: WebCrypto HMAC-SHA1

RFC 6238 implemented against the WebCrypto API — no Node crypto module needed. ±1 step tolerance for clock drift. 20-byte base32 secrets.

Secret encryption at rest: AES-256-GCM

LLM API keys, magic-link tokens, and other secrets are AES-GCM encrypted with a key derived from JWT_SECRET via PBKDF2. Auth tags prevent tampering.

Cron triggers

The Worker runs scheduled jobs without external orchestration. Two crons are active in production:

*/15 * * * *Revoke expired sessions, purge consumed magic-link tokens (soft-delete)
0 3 * * *Daily 03:00 UTC: hard-delete records soft-deleted > 90 days ago

Performance

0ms
Cold start
<1ms
JWT verify (edge)
~80ms
Worker → D1 query
300+
Edge PoPs

Want to see it live?

Cloudflare Console shows all 6 bindings + cron triggers in real time.

Open Cloudflare Console