Jede API, die externe Developer bedient, braucht Key Management. Die meisten Teams starten mit einem gehashten Random String in einer Datenbanktabelle und einem Check bei jedem Request. Dann wachsen die Anforderungen: Rate Limiting pro Key, Usage Tracking, Spend Caps für LLM-Calls, Key Rotation ohne Downtime, Webhooks bei Ablauf, ein Dashboard für Kunden.
Irgendwann hast du ein eigenes Produkt in deinem Produkt gebaut. KeyForge ist dieses Produkt, extrahiert und Open-Source.
Der Verify Hot Path
Jeder API-Call deiner Kunden geht durch die Key Verification. Ziel: sub-5ms p95 Latenz. Verifiziert mit k6 Load Tests (Ramp: 10 → 50 → 100 → 200 VUs, p95 < 10ms, p99 < 25ms, Error Rate < 1%).

Der Flow: SHA-256 Hash des Keys → Redis Cache Lookup (300s TTL) → bei Miss: PostgreSQL Query und Cache Write (Fire-and-Forget) → Key Status prüfen (enabled, nicht revoked mit Grace Period Handling, nicht expired) → Rate Limit Check via Lua Script → Token Budget Check → Spend Cap Check → Usage Increment (async, Fire-and-Forget) → Response.
Usage Increment und lastUsedAt Update blockieren den Response nicht. lastUsedAt wird als 5-Minuten Batch von Redis nach Postgres gesynct statt pro-Request Write.
import { KeyForge } from "@keyforge/sdk";
const kf = new KeyForge({ rootKey: "kf_root_xxx" });
// Express Middleware: eine Zeile
app.use(kf.middleware());
// Oder manuell
const result = await kf.verifyKey("kf_live_xxx", {
tokens: 1500,
cost: 0.045,
});
if (!result.valid) {
// result.code: INVALID | EXPIRED | REVOKED | RATE_LIMITED | BUDGET_EXCEEDED
}
Das SDK liefert Middleware für Express, Fastify, Hono und Next.js. Retry Logic mit Exponential Backoff ab 200ms, nur bei 5xx und Network Errors, nie bei 4xx. IETF-konforme Rate Limit Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After.
Key Lifecycle

Creation. crypto.randomBytes(32), Base64url encoded, Format: prefix_base64urlstring. Gespeichert wird nur der SHA-256 Hash. Kein Raw Key existiert je in der Datenbank.
Rotation. Grace Period (Default: 5 Minuten) in der alter und neuer Key gleichzeitig funktionieren. Kein “deploy new key, pray nothing breaks”.
Revocation. Ebenfalls mit Grace Period. Webhook wird gefeuert. Audit Log Entry.
Expiration. Cron Job prüft alle 5 Minuten. Abgelaufene Keys werden disabled, Webhook gefeuert, Audit Log geschrieben.
Constant-Time Comparison via crypto.timingSafeEqual bei der Verifikation. === auf Strings in Node.js early-returnt und ermöglicht Timing Attacks.
Drei Rate Limiting Algorithmen in Lua
Alle drei laufen als atomare Redis Lua Scripts. Ein EVALSHA Call mit Fallback zu EVAL bei Redis Restart. Ein Round Trip, keine Race Conditions.
Fixed Window. GET count → INCR → EXPIRE. Einfach, vorhersagbar, anfällig für Burst-at-Boundary.
Sliding Window. Gewichteter Durchschnitt über zwei Fenster: currentCount + (1 - elapsed/window) * previousCount. Smooth Limiting ohne Boundary-Artefakte.
Token Bucket. HMGET {tokens, lastRefill} → refill = floor(elapsed * refillRate) → tokens = min(max, tokens + refill) → HMSET + PEXPIRE. Burst-tolerant: erlaubt kurze Spitzen, erzwingt langfristiges Durchschnittslimit. 24h Safety TTL auf den Keys.
Pro Key konfigurierbar. Bei Redis-Ausfall: Fail Open. Besser ein unkontrollierter Request als ein geblockter zahlender Kunde.
Token Budgets und Spend Caps
Monatliche Limits auf Token-Verbrauch und Dollar-Spend. Gebaut für AI/LLM APIs, wo ein Request 100x mehr kosten kann als ein anderer. Redis Counters mit monatlichem Reset. Atomare Checks im gleichen Lua Script wie Rate Limiting.
Background Jobs (BullMQ)
Usage Flushing. Redis Hourly Buckets werden jede Minute nach Postgres geflusht. MULTI/EXEC für atomares Read-Delete, kein Double-Counting. Processor batcht 50 Events oder flusht alle 5 Sekunden. SCAN mit 200 Keys at a time.
lastUsedAt Sync. Alle 5 Minuten Bulk Update von Redis nach Postgres.
Key Expiration. Alle 5 Minuten: abgelaufene Keys disablen, Webhook feuern, Audit Log schreiben.
Audit Log Cleanup. Täglich um 3 Uhr: Free-Tier 30 Tage, Pro 365 Tage, Enterprise unbegrenzt.
Webhook Delivery. HMAC-SHA256 signiert: v1,HMAC(unix_timestamp.json_body, endpoint_secret). Headers: Webhook-Signature, Webhook-Timestamp, Webhook-Id. Exponential Backoff bis 5 Failures, dann Auto-Disable des Endpoints. 30-Sekunden Timeout. Response auf 4096 Bytes gekappt.
Embeddable React Portal
<KeyPortal /> Component das du in deine App droppst. Deine Kunden können ihre eigenen Keys verwalten, ohne dass du eine UI bauen musst. Shipped als @keyforge/react.
AWS Deployment

Terraform deployed die komplette Infrastruktur:
VPC mit Public/Private Subnet Split über 2+ AZs. ALB in Public Subnets, Compute in Private. Security Group Chain: ALB → ECS → RDS/Redis via SG References.
ECS Fargate. API (2+ Tasks) und Dashboard (2+ Tasks). Rolling Updates: 200% Max, 100% Min Healthy. enableShutdownHooks() für Graceful Shutdown, damit BullMQ Jobs drainen. Health Checks auf /health mit 15s Interval.
Auto-Scaling. API: CPU (70%) und ALB Request Count (1000 req/target), Min 2, Max 10. Dashboard: CPU only, Min 2, Max 5. Scale-Out 60s, Scale-In 300s Cooldown.
RDS PostgreSQL 16. Encrypted, gp3, Multi-AZ in Production. Performance Insights. 7 Tage Backup Retention.
ElastiCache Redis 7. allkeys-lru Eviction (256MB). 3 Tage Snapshots in Production.
6 CloudWatch Alarms: API CPU > 85%, RDS CPU > 80%, RDS Storage < 5GB, ALB 5xx > 50/5min, Unhealthy Targets, Health Check Failures. Alle routen zu SNS. Ops Dashboard: API CPU/Memory, ALB Latency/Count, RDS CPU/Connections/Storage, Redis CPU/Connections/Memory.
Secrets Manager für DATABASE_URL, REDIS_URL, Stripe Keys, Auth Secrets. ECR mit Image Scanning und Lifecycle Policies.
Database Design
Drizzle ORM. 8 Tabellen: workspaces (mit Plan und Stripe Integration), workspace_members (RBAC: Owner > Admin > Member > Viewer), api_keys (SHA-256 Hash, Rate Limits, Budgets, JSONB Metadata), usage_records (Time-Series mit Token Counts und Costs), webhook_endpoints, webhook_deliveries, audit_log, root_keys.
Strategische Indexes: api_keys_key_hash_idx für den Verify Hot Path, usage_records_key_period_idx für Zeitreihen, webhook_deliveries_status_idx für Retries, audit_log_workspace_timestamp_idx für Range Queries. bigint für Counters. timestamptz überall. Cascade Deletes auf FK Relationships.
CI/CD und Tests
72 Tests (28 Unit, 30 Integration, 14 Shared). Unit Tests mit Mock Redis + Postgres. Integration Tests mit echten Datenbanken und Full NestJS App Bootstrap. k6 Load Tests für den Verify Endpoint.
CI: Lint + Typecheck + Test auf PR/Push. Deploy: Docker Build (Layer Cache) → ECR Push → ECS Rolling Deploy. Terraform: Plan auf PR, Apply auf Merge.