Database Blueprint & Key Security
To support decentralized authorization, NexID Auth-DPoP divides state ownership between the Central Auth Server (identities and application registries) and the Downstream Application Servers (permissions and user profiles).
1. Central Auth Server Database (Cloudflare D1)
The Central Auth Server utilizes Cloudflare D1 (SQLite) as its primary global data store. It tracks registered downstream applications permitted to request backchannel upgrades and manages the core identity credentials.
-- Applications Register
-- Tracks client IDs and their corresponding verification hashes
CREATE TABLE registered_applications (
client_id TEXT PRIMARY KEY,
application_name TEXT NOT NULL,
api_key_hash TEXT NOT NULL, -- SHA-256 hash of the application's secret key
allow_custom_permissions INTEGER DEFAULT 1, -- Boolean: 1 = Allowed to inject custom bitmasks
created_at INTEGER DEFAULT (strftime('%s', 'now'))
);
-- Central User Store
-- Contains core credentials; does not store roles or permissions
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
created_at INTEGER DEFAULT (strftime('%s', 'now'))
);2. Downstream Application Database (Local SQL)
This database schema exists entirely at the application server origin (e.g., PostgreSQL, MySQL, SQLite). It holds application-specific business tables, local permission mappings, and a shadow user table mapping directly to the Central Auth’s user ID.
-- Local Shadow User Table
-- Maps directly to the 'sub' (subject) claim from the validated JWT
CREATE TABLE users (
id TEXT PRIMARY KEY, -- Maps to 'sub' from the JWT
display_name TEXT,
avatar_url TEXT
);
-- Local Application Permissions Registry
-- Powers of 2 represent individual bits (1, 2, 4, 8, etc.)
CREATE TABLE local_permissions (
id INTEGER PRIMARY KEY, -- Powers of 2: 1, 2, 4, 8, etc.
name TEXT UNIQUE NOT NULL,
description TEXT
);
-- User-Permission Assignments
-- Maps users to their specific roles/permissions locally
CREATE TABLE user_permissions (
user_id TEXT,
local_permission_id INTEGER,
PRIMARY KEY (user_id, local_permission_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (local_permission_id) REFERENCES local_permissions(id) ON DELETE CASCADE
);Retrieving the Permission Bitmask
To fetch a user’s local permission bitmask, the application’s integration library executes a fast query using the SUM function. Because permissions are represented as distinct bits (powers of 2), summing them computes the combined bitmask value:
SELECT IFNULL(SUM(local_permission_id), 0) as user_bitmask
FROM user_permissions
WHERE user_id = ?;3. Security Architecture: The “Application Auth Key”
To prevent malicious clients or unauthorized services from spoofing user permissions during the upgrade phase, we enforce strict server-to-server validation.
API Key Generation
When a developer registers a downstream application on the Central Auth Platform:
- The platform generates a high-entropy secret token (e.g.,
sk_live_abc123...). - This secret is displayed to the developer once and must be stored securely in their server-side environment variables (
APP_AUTH_KEY).
Zero-Knowledge Secret Storage
To maintain high security, the Central Auth Server never stores the plain text secret in its database.
- The worker computes a one-way SHA-256 hash of the plain text secret.
- Only the SHA-256 hash is saved in the
api_key_hashfield of theregistered_applicationstable.
Upgrade Validation Handshake
When the application server calls /api/tokens/upgrade:
- It sends the plain text
APP_AUTH_KEYin theAuthorizationbearer header. - The Cloudflare Worker hashes the incoming header value using SHA-256.
- The Worker executes a constant-time SQL lookup against the
registered_applicationstable to find a matchingapi_key_hash.
Security Advisory
The APP_AUTH_KEY must never be exposed to client-side code, web browers, or mobile applications. Compromise of this key would allow attackers to inject arbitrary permission bitmasks.