Architecture Blueprint: NexID Auth-DPoP
This document specifies the architecture, design choices, data schemas, and cryptographic workflows for NexID Auth-DPoP, a high-performance, globally distributed authentication and authorization system designed to run entirely on the Cloudflare Edge Network.
1. Executive Summary
Traditional authentication systems introduce significant latency by forcing application servers to perform database roundtrips or centralized API calls to verify user permissions on every request.
NexID Auth-DPoP eliminates this latency by executing token generation, authorization state compression, and cryptographic proof-of-possession verification at the edge. By using Ed25519 (EdDSA) for token signing, integer-based bitmask permissions for ultra-compact authorization payloads, and DPoP (Demonstrating Proof-of-Possession) to cryptographically bind tokens to clients, the system achieves sub-millisecond local token validation while remaining highly secure against token-theft and replay attacks.
2. Key Technology Stack
The following core technologies power the NexID Auth-DPoP runtime:
| Component | Technology | Purpose / Role |
|---|---|---|
| Compute Runtime | Cloudflare Workers (V8) | Global, low-latency execution of auth logic. |
| Primary Database | Cloudflare D1 (SQLite) | Storage for users, roles, permissions, and client registrations. |
| Global Cache & Limit | Upstash Redis (via REST) | Globally replicated, low-latency rate limiting and DPoP proof handshake storage. |
| Fast-Path Verification | Bloom Filters | Fast client/user existence checks to prevent database resource exhaustion. |
| Cryptographic Suite | EdDSA (Ed25519) | Ultra-fast token signing with tiny key footprint and low CPU usage. |
| Security Standard | DPoP (RFC 9449) | Cryptographic proof-of-possession to prevent token hijacking. |
3. High-Level Architecture Flow
Request Lifecycle
- Authentication Request: The client initiates authentication by sending credentials along with a unique DPoP proof (a signed JWT containing the client’s ephemeral public key).
- Pre-flight Verification: The Cloudflare Worker validates the credentials. It performs a fast-path existence check using a Bloom filter to avoid D1 database lookups for invalid identifiers.
- Token Compilation: The Worker queries Cloudflare D1 for user roles, compresses roles into a single bitwise integer, and signs an Access Token (using the Ed25519 private key). The token payload includes the bitmask and the thumbprint (
jkt) of the client’s public key. - Local Verification: Application servers cache the authorization server’s JWKS (JSON Web Key Set). When the client calls an application endpoint with the token, the application server validates the signature and performs an instantaneous bitwise
ANDoperation locally in CPU memory to grant or deny access.
4. Permission Bitmask System
Instead of passing an array of string permissions (e.g., ["posts:read", "posts:write"]) which increases token size and processing time, NexID Auth uses bitwise operations.
Bitmask Mapping Configuration
Permissions are mapped to powers of 2 (individual bits in an integer):
enum Permissions {
NONE = 0, // 00000000
READ_POSTS = 1 << 0, // 00000001 (Decimal: 1)
WRITE_POSTS = 1 << 1, // 00000010 (Decimal: 2)
DELETE_POSTS = 1 << 2, // 00000100 (Decimal: 4)
MANAGE_USERS = 1 << 3, // 00001000 (Decimal: 8)
BILLING = 1 << 4, // 00010000 (Decimal: 16)
}Assigning & Merging Permissions (At Edge)
If a user is assigned READ_POSTS and WRITE_POSTS, their bitmask is computed using the bitwise OR (|) operator:
Bitmask = READ_POSTS | WRITE_POSTS = 1 | 2 = 3 (Binary: 00000011)Verifying Permissions (At App Server)
To check if a request to delete a post is authorized, the application server extracts the permissions claim from the verified JWT and applies the bitwise AND (&) operator:
const required = Permissions.DELETE_POSTS; // 4 (00000100)
const userPerms = jwt.payload.permissions; // 3 (00000011)
const isAuthorized = (userPerms & required) === required;
// (00000011 & 00000100) => 00000000 (Decimal: 0)
// 0 !== 4 -> Access Denied!This evaluation runs in microseconds, requires no memory overhead, and keeps token sizes exceptionally small.
5. Token Cryptography: EdDSA (Ed25519) vs. RSA
NexID Auth utilizes EdDSA (specifically Ed25519) as its primary signing algorithm.
Why Ed25519 over RSA?
- CPU Execution Limits: Cloudflare Workers are strictly billed and throttled based on CPU execution time. An Ed25519 sign operation is up to 10x faster than an RSA-2048 sign operation, significantly reducing Worker execution time and billable usage.
- Payload Footprint: An RSA-2048 key requires a 256-byte signature, ballooning the HTTP header payload. An Ed25519 key requires only a 32-byte public key and a 64-byte signature, yielding compact JWTs ideal for high-frequency edge transit.
- Deterministic Signatures: Unlike traditional ECDSA, EdDSA does not require a high-entropy random number generator at the time of signing. It is deterministic, preventing private key leakage through flawed random entropy pools at the edge.
6. DPoP (Demonstrating Proof-of-Possession)
Standard Bearer tokens are vulnerable to intercept-and-replay attacks (if a token is stolen from client storage, the attacker has complete access). NexID Auth mitigates this via DPoP (RFC 9449).
How It Works
- Client Key Generation: The client generates an ephemeral, non-exportable cryptographic key pair (typically an asymmetric curve like P-256 or Ed25519) inside browser secure storage or hardware enclaves.
- DPoP Proof: For every request to the auth or app server, the client creates a temporary, short-lived JWT called the DPoP Proof.
- It is signed by the client’s private key.
- Its header contains the client’s public key (
jwk). - Its payload contains the current HTTP method (
htm), the target URI (htu), a unique identifier (jtito prevent replay), and a timestamp (iat).
- Token Binding (
cnfclaim): When generating the main access token, the Auth Server hashes the client’s public key to create a JWK thumbprint (jkt) and bakes it into the access token payload:{ "sub": "user_12345", "permissions": 3, "cnf": { "jkt": "0Z_A4...T8pQ" } } - Validation: The application server verifies:
- The validity of the main access token’s signature.
- The validity of the DPoP proof’s signature.
- That the thumbprint of the public key in the DPoP proof matches the
cnf.jktclaim inside the access token.
- Replay Attack Check: The unique identifier (
jti) of the DPoP proof is registered in Upstash Redis with an expiration of 2 minutes. If the samejtiis reused, the request is immediately rejected.
7. Cloudflare D1 Database Schema
To maintain global low latency, the primary state is written to Cloudflare D1. D1 replicates read access globally to ensure DB queries resolve near the client.
-- Users Table
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
created_at INTEGER DEFAULT (strftime('%s', 'now'))
);
-- Permissions Register (Mapped to bit values)
CREATE TABLE permissions (
id INTEGER PRIMARY KEY, -- Must be powers of 2 (1, 2, 4, 8, etc.)
name TEXT UNIQUE NOT NULL,
description TEXT
);
-- Roles Table
CREATE TABLE roles (
id TEXT PRIMARY KEY,
name TEXT UNIQUE NOT NULL
);
-- Role-Permission Mapping
CREATE TABLE role_permissions (
role_id TEXT,
permission_id INTEGER,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
);
-- User-Role Mapping
CREATE TABLE user_roles (
user_id TEXT,
role_id TEXT,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);Consolidating Bitmask via SQL
We can retrieve a user’s unified permission bitmask in a single query:
SELECT IFNULL(SUM(rp.permission_id), 0) as user_bitmask
FROM user_roles ur
JOIN role_permissions rp ON ur.role_id = rp.role_id
WHERE ur.user_id = ?1;8. Deployment and GitOps Synchronization
To enforce strict, audit-friendly access control, the mapping of strings to integer bitmasks is synchronized using a GitOps workflow:
- Configuration File: Developer teams define permissions and assignments in a central declarative file (e.g.,
permissions.yamlor JSON) in a Git repository. - CI/CD Pipeline: On pull request approval and merge:
- A script validates that no two permissions share the same bit value (preventing collisions).
- A migration script updates the
permissionstable in the Cloudflare D1 production database. - The TypeScript type-definitions (e.g.,
Permissionsenum) are autogenerated and published to a shared private package or internal dependency registry, ensuring application servers and auth workers are always in perfect sync.