API Key Management: Rotation & Revocation 2026
API Key Management: Generation, Rotation, and Revocation
API keys are the most common authentication method for APIs. They're simple, effective, and universally understood. But simplicity creates risk — a leaked key is a breached system. Secure key management covers the full lifecycle: generation, storage, distribution, rotation, and revocation.
API Key Lifecycle
Generate → Distribute → Use → Monitor → Rotate → Revoke
↑ |
└────────────────────────────────────────┘
Key Generation
Format Matters
Good API keys are:
- Identifiable — prefixed so you know what they are
- Unique — cryptographically random, no collisions
- Secure — enough entropy to resist brute force
Prefix patterns from top APIs:
| API | Key Format | Purpose |
|---|---|---|
| Stripe | sk_live_..., sk_test_... | Environment + type |
| GitHub | ghp_..., ghs_..., ghu_... | Scope (personal, server, user-to-server) |
| OpenAI | sk-proj-... | Project-scoped |
| AWS | AKIA... (20 chars) | IAM access key |
| Twilio | 34-char hex string | Account SID + Auth Token |
Recommended format:
{provider}_{environment}_{random}
Examples:
myapi_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
myapi_test_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4
Generation Best Practices
✅ Use crypto.randomBytes(32) or equivalent (256 bits of entropy)
✅ Use a prefix that identifies the key type and environment
✅ Make keys long enough (40+ characters) to prevent brute force
✅ Generate server-side only — never on the client
❌ Don't use UUIDs (only 122 bits of entropy, predictable structure)
❌ Don't use sequential IDs
❌ Don't derive keys from user data (email, username)
❌ Don't use short keys (<32 characters)
Key Storage
Server-Side (Your Database)
Never store API keys in plain text. Hash them like passwords:
What you store: SHA-256(api_key) or bcrypt(api_key)
What the user sees: sk_live_a1b2c3d4... (shown once, never again)
What you compare: SHA-256(incoming_key) === stored_hash
Show the full key exactly once — at creation time. After that, show only the last 4 characters: sk_live_...o5p6.
Key Metadata
Store alongside the hash:
| Field | Purpose |
|---|---|
key_hash | SHA-256 hash for lookup |
key_prefix | First 8 chars for identification |
key_suffix | Last 4 chars for display |
user_id | Owner of the key |
name | User-defined label ("Production Server") |
scopes | Permissions (read, write, admin) |
created_at | When the key was generated |
last_used_at | Last successful authentication |
expires_at | Expiration date (null = never) |
rate_limit | Per-key rate limit override |
ip_allowlist | Restrict to specific IPs |
Client-Side (Developer's App)
Developers need to store API keys securely in their applications:
| Environment | Storage Method | Security |
|---|---|---|
| Backend server | Environment variables | Good |
| Backend server | Secrets manager (AWS SM, Vault) | Best |
| Mobile app | Keychain (iOS) / Keystore (Android) | Good |
| Browser | Never store API keys in frontend code | N/A |
| CI/CD | Pipeline secrets (GitHub Secrets, etc.) | Good |
Never commit API keys to source code. Use environment variables or secret managers.
Key Scoping
Permission Levels
Not all keys should have the same access:
| Scope | Access | Use Case |
|---|---|---|
read | GET only | Public dashboards, read-only integrations |
write | GET + POST + PUT | Standard API usage |
admin | Full access + key management | Account administration |
billing | Billing endpoints only | Finance integrations |
Resource Scoping
Limit keys to specific resources:
{
"key": "sk_live_...",
"scopes": ["orders:read", "orders:write", "products:read"],
"resources": {
"organizations": ["org_123"],
"projects": ["proj_456", "proj_789"]
}
}
A key scoped to orders:read can't access user data, even if the API has user endpoints.
Environment Separation
Always separate test and production keys:
| Key Type | Prefix | Access | Billing |
|---|---|---|---|
| Test | sk_test_ | Sandbox only | No charges |
| Live | sk_live_ | Production | Real charges |
Test keys should never work in production. Production keys should never work in sandbox.
Key Rotation
Why Rotate
- Reduce blast radius of leaked keys
- Comply with security policies (SOC 2, PCI DSS)
- Limit exposure window
- Force key hygiene
Rotation Policy
| Key Type | Rotation Period | Enforcement |
|---|---|---|
| Production API keys | Every 90 days | Recommended, warn at 60 days |
| Service-to-service keys | Every 30 days | Automated rotation |
| CI/CD keys | Every 90 days | Pipeline-enforced |
| Admin keys | Every 30 days | Required |
| Test keys | No rotation needed | Optional |
Graceful Rotation (Overlap Period)
Never invalidate the old key immediately. Allow an overlap period:
Day 0: Generate new key → Both old and new keys work
Day 1-7: Developer updates their applications to use new key
Day 7: Old key is revoked
During overlap: Both keys authenticate successfully
After overlap: Only new key works
Automated Rotation
For service-to-service keys, automate the entire process:
1. Secrets manager generates new key
2. New key is registered with the API
3. Secrets manager updates the consuming service's config
4. Service restarts or hot-reloads the new key
5. Old key is revoked after grace period
6. Audit log records the rotation
Tools: AWS Secrets Manager, HashiCorp Vault, Doppler, 1Password Connect
Key Revocation
When to Revoke
| Trigger | Action | Urgency |
|---|---|---|
| Key leaked in public repo | Immediate revocation | Emergency |
| Employee leaves company | Revoke their keys | Same day |
| Key compromised | Immediate revocation | Emergency |
| Key unused for 90+ days | Revoke with notification | Low |
| Key rotation complete | Revoke old key | Scheduled |
Revocation Process
1. Mark key as revoked in database (don't delete — keep for audit)
2. Clear key from all caches
3. Return 401 with clear error: "API key has been revoked"
4. Log the revocation event with reason
5. Notify the key owner (email, webhook, dashboard alert)
6. If emergency: check for unauthorized usage in recent logs
GitHub's Automatic Revocation
GitHub scans public repositories for leaked API keys and automatically:
- Notifies the API provider
- Provider revokes the key
- Notifies the developer
If you're an API provider, join GitHub's Secret Scanning Partner Program to get automatic leak notifications.
Monitoring and Alerts
What to Monitor
| Signal | Indicates | Alert Threshold |
|---|---|---|
| Key used from new IP | Potential compromise | Any new IP (notify) |
| Sudden usage spike | Abuse or compromise | 5x normal volume |
| Key used from unexpected country | Potential compromise | Any unexpected location |
| Failed auth attempts | Brute force attack | 10+ failures in 1 minute |
| Key approaching expiration | Needs rotation | 14 days before expiry |
| Key unused for 60+ days | Orphaned key | Notify owner |
Audit Logging
Every key event should be logged:
{
"event": "api_key.used",
"key_prefix": "sk_live_a1b2",
"ip": "203.0.113.42",
"endpoint": "POST /api/orders",
"timestamp": "2026-03-08T14:30:00Z",
"user_agent": "MyApp/2.1",
"status": 200
}
Log these events: key.created, key.used, key.rotated, key.revoked, key.expired, key.auth_failed.
Patterns from Top APIs
| API | Notable Practice |
|---|---|
| Stripe | Test/live prefix, last 4 visible, scope by mode |
| GitHub | Fine-grained tokens with per-repo permissions, auto-expiry |
| AWS | Access key + secret key pair, IAM policy-based scoping |
| Google Cloud | Service account JSON keys, workload identity federation |
| Twilio | Account SID + Auth Token, sub-account isolation |
Key Management at Scale
Managing API keys for hundreds of customers is operationally straightforward. Managing them for hundreds of thousands introduces problems that the basics don't address.
Key lookup performance. Authenticating a key on every API request must be fast — you're adding it to the critical path of every authenticated call. Hashing the incoming key and looking up the hash in a database is correct, but needs to be sub-millisecond. Use a key-value cache (Redis or Memcached) as the primary lookup, backed by the database. Cache TTL should be short — 60 to 300 seconds — so revocations propagate quickly. A revoked key that still authenticates from cache for 5 minutes is operationally acceptable in most systems; one that remains valid for hours is not.
Bulk revocation events. When an organization member leaves, you may need to revoke many keys simultaneously. When a security incident occurs, you may need to force-rotate all customer keys at once. Design bulk revocation as a first-class operation: a background job that processes revocations in batches, writes audit records, sends notifications to owners, and handles partial failures gracefully. Revoking thousands of keys synchronously in a single web request is not viable.
Orphaned key cleanup. In any large deployment, keys will be created and forgotten. A regular cleanup process — identify keys unused for more than 90 days, notify the owner with a 14-day warning before revocation, then revoke if no response — reduces attack surface and keeps your key inventory reflective of actual usage.
Short-Lived Tokens vs. Long-Lived Keys
Traditional API keys are long-lived credentials. Once issued, they're valid until explicitly revoked. This is convenient: a developer pastes the key into their configuration and it works indefinitely. The risk is symmetric: a leaked key is valid indefinitely too.
Short-lived tokens — OAuth 2.0 access tokens are the most common example — expire automatically, bounding the exposure window for any compromised credential. The tradeoff is implementation complexity. Consuming applications must handle 401 responses when tokens expire, refresh them using a refresh token or client credentials flow, and retry the original request. For sophisticated server-side integrations with proper secret management, this is manageable. For developer quickstarts or CI/CD scripts, the friction meaningfully reduces adoption.
The pragmatic approach most mature API providers use: offer both. Long-lived API keys for developer exploration, testing, and CI/CD pipelines where the lifecycle is well-understood. Short-lived OAuth tokens for production integrations where automated rotation is expected. GitHub's fine-grained personal access tokens — which support 7, 30, or 90-day expiration and per-repository scoping — model this dual approach well.
Common Mistakes
| Mistake | Impact | Fix |
|---|---|---|
| Storing keys in plain text | Database breach = all keys compromised | Hash with SHA-256 |
| No key rotation policy | Leaked keys stay valid forever | 90-day rotation policy |
| Same key for test and prod | Test code accidentally hits production | Separate keys with prefixes |
| No scope restrictions | Every key has admin access | Principle of least privilege |
| Showing full key after creation | Keys visible in dashboards, emails | Show once, then mask |
| No monitoring on key usage | Can't detect compromise | Alert on anomalous patterns |
Securing your API keys? Explore API security tools and best practices on APIScout — comparisons, guides, and developer resources.
Related: Best Webhook Management APIs in 2026, How AI Is Transforming API Design and Documentation, API Breaking Changes Without Breaking Clients