API Key Security Best Practices
Complete guide to protecting your credentials
TL;DR
TL;DR: Store API keys in environment variables, never in code. Use different keys for development and production. Limit key permissions to only what's needed. Rotate keys regularly (every 90 days for critical services). Monitor usage for anomalies. Have a rotation plan ready before you need it.
1. Storage Best Practices
Do This
- Store keys in environment variables
- Use your hosting platform's secret management
- Keep production keys separate from development keys
- Use a .env.example file to document required variables
Never Do This
- Hardcode keys in source files
- Commit .env files to git
- Store keys in frontend/client-side code
- Share keys via Slack, email, or other chat tools
- Use the same key for development and production
// BAD: Hardcoded key
const stripe = new Stripe('sk_live_xxxxx');
// GOOD: Environment variable
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
// BETTER: With validation
const stripeKey = process.env.STRIPE_SECRET_KEY;
if (!stripeKey) {
throw new Error('STRIPE_SECRET_KEY is required');
}
const stripe = new Stripe(stripeKey);
2. Key Scoping and Permissions
Apply the principle of least privilege:
| Approach | Risk Level | Recommendation |
|---|---|---|
| Full access key | High | Avoid if possible |
| Read-only key | Medium | Use when only reading data |
| Scoped key (specific resources) | Low | Preferred approach |
| Time-limited key | Lowest | Use for CI/CD, one-time tasks |
Service-Specific Examples
# Stripe: Use restricted keys
# Dashboard > Developers > API keys > Create restricted key
# Only enable permissions needed (e.g., "Charges: Read" for analytics)
# AWS: Use IAM policies
# Create policies with specific actions and resources
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
# GitHub: Use fine-grained PATs
# Settings > Developer settings > Fine-grained tokens
# Select specific repositories and permissions
3. Key Rotation Strategy
| Key Type | Rotation Frequency | Why |
|---|---|---|
| Payment keys (Stripe, etc.) | 90 days | High financial risk |
| Database credentials | 90 days | Data access risk |
| Third-party API keys | 180 days | Moderate risk |
| Public/anon keys | As needed | Low risk if RLS enabled |
| Compromised keys | Immediately | Active threat |
Rotation Checklist
Before Rotating
- Generate new key in service dashboard
- Document the new key securely
- Prepare environment variable updates
During Rotation
- Update production environment variables
- Deploy or restart affected services
- Verify new key is working
- Revoke old key
After Rotating
- Update local development environments
- Notify team members
- Update any documentation
- Schedule next rotation
4. Monitoring and Alerting
Set up monitoring to detect compromised keys early:
- Usage alerts: Set thresholds for API calls (e.g., alert if OpenAI usage exceeds $100/day)
- Geographic alerts: Flag API calls from unexpected locations
- Rate anomalies: Sudden spikes in usage often indicate compromise
- Failed auth attempts: Multiple failures may indicate key scanning
Service-Specific Monitoring
# OpenAI: Set usage limits
# Settings > Limits > Set monthly budget and alerts
# Stripe: Enable webhook for suspicious activity
# Dashboard > Developers > Webhooks > radar.early_fraud_warning
# AWS: CloudWatch alarms
# Set billing alarms and API call anomaly detection
5. Incident Response Plan
Have a documented plan before you need it:
- Detect: How did you learn the key was compromised?
- Contain: Immediately rotate or revoke the key
- Assess: Check logs for unauthorized usage
- Remediate: Deploy new key, fix the exposure source
- Review: Document what happened and prevent recurrence
Speed Matters
Automated scanners find exposed keys within minutes. AWS keys have been used for crypto mining within 5 minutes of exposure. Have your rotation process documented so anyone on the team can execute it quickly.
6. Development vs Production
| Environment | Key Type | Example |
|---|---|---|
| Development | Test/sandbox keys | sk_test_xxxxx |
| Staging | Test keys | sk_test_xxxxx |
| Production | Live keys | sk_live_xxxxx |
Configure your CI/CD to use different environment variable sets for each environment. Never use production keys in development or testing.
Should I encrypt API keys at rest?
If using environment variables in a trusted hosting platform (Vercel, Railway, etc.), they're already encrypted at rest. For self-hosted solutions, consider using a secrets manager like HashiCorp Vault or AWS Secrets Manager.
How do I share API keys with team members?
Use your hosting platform's team features (Vercel team settings, etc.) or a secrets manager. Never share via Slack, email, or shared documents. If you must share directly, use encrypted channels and immediately rotate after onboarding.
Are Supabase anon keys really safe to expose?
Supabase anon keys are designed to be public when used with Row Level Security (RLS). They're similar to Firebase's public config. The key identifies your project; RLS policies control access. The service_role key must stay secret.
Related guides:How to Hide API Keys · How to Rotate API Keys · How to Enable Secret Scanning