Implementing Persistent JWT Signing Keys with PostgreSQL and Envelope Encryption
These articles are AI-generated summaries. Please check the original sources for full details.
Persistent JWT Signing Keys with PostgreSQL
The @saurbit/oauth2-jwt system provides high-security key management by separating public and private key storage interfaces. In-memory stores fail in production as server restarts or multiple instances invalidate all previously issued tokens.
Why This Matters
While tutorials often use in-memory stores for simplicity, production systems face the reality of ephemeral server instances and horizontal scaling. Storing private keys in plaintext or failing to synchronize keys across pods creates immediate authentication failures; envelope encryption bridges this gap by securing the database layer while ensuring high availability.
Key Insights
- Envelope Encryption uses a random 256-bit DEK per key pair, which is then wrapped by a master KEK stored only in environment variables.
- Database persistence ensures that tokens issued before a server restart or across different pods remain verifiable by resource servers.
- Key rotation is automated by the JwksRotator which checks the created_at timestamp of the active private key record.
- Overlap periods are managed by retaining expired public keys in the public_keys table until their TTL is reached, allowing for seamless rotation.
Working Examples
PostgreSQL schema for persistent key storage including a single-row constraint for active private keys.
CREATE TABLE IF NOT EXISTS private_keys (key_id character varying(255) NOT NULL, id integer NOT NULL DEFAULT 1, private_key text NOT NULL, wrapped_dek text NOT NULL, expires_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL DEFAULT now(), CONSTRAINT private_keys_pkey PRIMARY KEY (key_id), CONSTRAINT private_keys_id_unique UNIQUE (id), CONSTRAINT id CHECK (id = 1)); CREATE TABLE IF NOT EXISTS public_keys (key_id character varying(255) NOT NULL, public_key text NOT NULL, expires_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL DEFAULT now(), CONSTRAINT public_keys_pkey PRIMARY KEY (key_id));
Implementation of JwksKeyStore using envelope encryption (AES-256-GCM) with a Data Encryption Key (DEK) and Master Key (KEK).
export const jwksStore: JwksKeyStore = { async storeKeyPair(kid: string, privateKey: object, publicKey: object, ttl: number) { const dekRaw = crypto.getRandomValues(new Uint8Array(32)); const encryptedPrivateKey = await encrypt(JSON.stringify(privateKey), dekRaw); const wrappedDek = await encrypt(uint8ArrayToBase64(dekRaw), MASTER_KEY_RAW); const expirationTime = Date.now() + ttl * 1000; const privateKeyRecord: PrivateKeyRecord = { keyId: kid, privateKey: uint8ArrayToBase64(encryptedPrivateKey), wrappedDek: uint8ArrayToBase64(wrappedDek) }; const publicKeyRecord: PublicKeyRecord = { keyId: kid, publicKey: JSON.stringify(publicKey) }; await saveKeyPairRecord(privateKeyRecord, publicKeyRecord, expirationTime); } };
Practical Applications
- Multi-instance OIDC servers: Using a shared PostgreSQL database ensures token consistency across pods. Pitfall: Hardcoding the MASTER_KEY in source control leads to total system compromise if the repository is leaked.
- Automated key rotation: Systems using JoseJwksAuthority generate new RSA pairs every 91 days while maintaining old public keys for verification. Pitfall: Setting rotation intervals longer than public key TTLs causes a verification gap.
References:
Continue reading
Next article
Essential Observability: 3 Critical Alerts for LLM Systems
Related Content
Implementing Production-Grade JWT Authentication with Express and TypeScript
Build a secure authentication system using Access/Refresh tokens, HTTP-only cookies, and Mongoose middleware for robust session management.
Secure Your Node.js Workflow Against Shai-Hulud Worms with np-audit
Secure your dev environment from Shai-Hulud worms that compromised 700+ npm packages and 14,000 secrets in 48 hours using np-audit.
Securing Remote Access: A Technical Guide to ssh-keygen
Learn how to use ssh-keygen to implement public-key authentication and secure server access using RSA, ECDSA, and Ed25519 algorithms.