Context
With the login gate removed in #3115, all visitors can now sign in. The next step is letting authenticated users create and manage their own API keys so they can integrate with the WorldMonitor API programmatically.
Per @koala73's direction — open things up and let users self-serve.
What exists today
- Clerk-based user auth (login, JWT, roles)
- OAuth 2.0 token flow (auth code + refresh tokens via Redis)
- Entitlements/tier system in Convex (
apiAccess, apiRateLimit per plan)
- API key validation middleware (
X-WorldMonitor-Key checked against static WORLDMONITOR_VALID_KEYS env var)
- SHA-256 key hashing in the OAuth flow
- Product catalog with API-tier plans (API Starter, API Business, Enterprise)
What's missing
Backend
Frontend
Out of scope (for now)
- Usage-based / metered billing via Dodo (currently all plans are flat-rate)
- Per-endpoint scoping of API keys
- API usage dashboard / analytics
Notes
- Key format:
wm_<random base64url> (consistent with existing openssl rand -hex 24 | sed 's/^/wm_/' convention in docs)
- Store only SHA-256 hash in DB, never plaintext
- Entitlements already define rate limits per tier (0 / 60 / 300 / 1000 req/min) — just need to enforce them
🤖 Generated with Claude Code
Context
With the login gate removed in #3115, all visitors can now sign in. The next step is letting authenticated users create and manage their own API keys so they can integrate with the WorldMonitor API programmatically.
Per @koala73's direction — open things up and let users self-serve.
What exists today
apiAccess,apiRateLimitper plan)X-WorldMonitor-Keychecked against staticWORLDMONITOR_VALID_KEYSenv var)What's missing
Backend
userApiKeystable — schema:userId,name,keyPrefix(first 8 chars for display),keyHash(SHA-256),createdAt,lastUsedAt,revokedAtcreateApiKey,listUserApiKeys,revokeApiKey_api-key.js/premium-check.tsto look up user-owned keys in Convex (not just static env var list)apiRateLimitfrom entitlements (currently stored but never checked)Frontend
Out of scope (for now)
Notes
wm_<random base64url>(consistent with existingopenssl rand -hex 24 | sed 's/^/wm_/'convention in docs)🤖 Generated with Claude Code