Why API Keys Need a Specific Design
An API key is not just a random string — it's a credential that will be embedded in code, passed through CI/CD pipelines, logged in request headers, and copied into config files by developers who may not always be careful. Good API key design accounts for these failure modes upfront.
The industry has converged on a pattern: a readable prefix that identifies the key's type and environment, followed by a cryptographically random body long enough that guessing is computationally infeasible. This design gives you three things: scannability (automated tools can find leaked keys by pattern), safety (test keys can't accidentally hit production endpoints), and security (128+ bits of entropy on the random body).
How Stripe does it — the gold standard
Stripe's key format is widely copied because it solves every relevant problem elegantly:
sk_live_— live secret key (server-side only, full access)pk_live_— live publishable key (safe for client-side code)sk_test_— test secret key (no real charges)pk_test_— test publishable key (safe for client-side test code)whsec_— webhook signing secret (rotate on vendor change)rk_live_— restricted key (scoped to specific API endpoints)
The prefix makes the environment and capability immediately visible. A developer reading config can tell at a glance whether a key is live or test, secret or publishable, restricted or full-access. This is the pattern to follow for your own service.
Designing Your Prefix Convention
If you're building an API that issues keys, establish your prefix convention before your first user. Changing it after launch means issuing new keys to all existing users and deprecating the old format — painful.
| Key type | Recommended prefix | Body length | Notes |
|---|---|---|---|
| Production API key | sk_live_ or api_live_ | 32 chars | Server-side only. Full entropy. |
| Development/test key | sk_test_ or api_dev_ | 32 chars | Can be stored less securely in dev configs. |
| Public/embeddable key | pk_ or pub_ | 24 chars | Safe for client code. Should only allow read or non-destructive actions. |
| Webhook secret | whsec_ | 32–48 chars | Used to sign payloads, not to auth API calls. Rotate on every webhook endpoint change. |
| Service-to-service token | svc_ or int_ | 48 chars | Higher entropy for internal services where rotation is automated. |
| Personal access token | pat_ or ghp_ | 36 chars | User-scoped. Should expire or be revocable individually. |
The Secret Rotation Protocol
Key rotation is the most important security practice most teams skip. The reason to rotate isn't just that a key might be compromised — it's that you want to discover a compromise quickly, not months later when you finally rotate. A key that's been sitting unchanged for 18 months has an unknown exposure window. A key rotated every 90 days has a known maximum exposure window.
Zero-downtime rotation pattern
- Generate a new key using this tool.
- Add the new key to your platform alongside the old key (most APIs accept multiple active keys per account).
- Update all services to use the new key (deploy, verify health checks pass).
- Revoke the old key only after confirming all services are using the new one.
Never revoke the old key before deploying the new one. The brief overlap period is intentional — it prevents downtime during rotation.
Storing Keys in Deployment Platforms
The correct way to store API keys in production is encrypted environment variables, never in committed code. Modern deployment platforms make this easy:
- Cloudflare Workers Secrets — encrypted at rest, injected as env vars at runtime, not visible after creation even to the account owner.
- Vercel Environment Variables — per-environment (preview/production/development), encrypted, visible only on first creation.
- AWS Secrets Manager — native rotation automation, IAM-controlled access, full audit trail.
- HashiCorp Vault — self-hosted option for organizations that can't use cloud-managed secrets.
Whatever platform you use, the principle is the same: the secret lives in the platform's encrypted store and is injected into your runtime environment at deploy time. Your codebase contains only the variable name, never the value.
Implementing Key Hashing on Your Backend
If your service issues API keys to users, you must hash them before storage. The pattern mirrors password storage:
- At creation: generate key → show to user once → store
sha256(key)in database - At verification: receive key in request header → compute
sha256(key)→ look up hash in database - At rotation: generate new key → show once → store new hash → invalidate old hash
If your database is ever compromised, attackers get SHA-256 hashes, not raw keys. SHA-256 is appropriate here (unlike passwords) because API keys already have sufficient entropy — an attacker cannot precompute a rainbow table for 32-character random strings.