API Key Best Practices for Production Systems
If you're searching for "API key best practices," you probably already have keys in production and want to know if you're handling them correctly — or you're about to ship something that touches a third-party API and don't want to end up as a cautionary tweet. The short answer: never hardcode keys, scope them as narrowly as possible, rotate them on a schedule, and monitor usage so you notice compromise before it becomes an incident.
This isn't a definitions post. It's a working set of practices you can apply today, whether you're calling an AI provider, a payment processor, or your own internal services.
Never Commit Keys to Source Control
This is the most common failure mode, and it's almost always accidental. A developer pastes a key into a test script, commits it "temporarily," and it's now permanently in git history — even if the file is deleted in a later commit.
Practical steps:
- Add
.envand any secrets files to.gitignorebefore you create them, not after. - Use a pre-commit hook or a tool like
git-secrets/gitleaksto scan for key patterns before they leave your machine. - If a key does leak, revoke it immediately. Rewriting git history does not help — assume anyone who cloned the repo already has it.
- Scan public repos for your own key prefixes periodically if you maintain open-source projects that reference your services.
# example .gitignore entry
.env
.env.local
*.pem
secrets/
Store Keys as Environment Variables, Not Config Files
Environment variables keep secrets out of your codebase and make it trivial to use different keys per environment (dev, staging, production) without touching code.
const apiKey = process.env.SUBTOAPI_KEY;
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "claude-3-5-sonnet",
messages: [{ role: "user", content: "Summarize this ticket." }]
})
});
For anything beyond a single-developer project, use a proper secrets manager — AWS Secrets Manager, HashiCorp Vault, Doppler, or your platform's built-in secrets store (Vercel, Fly.io, Railway all have one). Environment variables are fine for the app runtime, but the source of truth should be a system with access logs and versioning, not a .env file sitting on someone's laptop.
Scope Keys to the Minimum Required Access
A key that can do everything is a key that can break everything. If your provider supports scoped or role-restricted keys, use them:
- Read-only keys for services that only need to fetch data.
- Separate keys per environment so a staging leak doesn't expose production.
- Separate keys per application or team, so you can revoke one without taking down everything else.
This is exactly why SubToAPI issues per-application keys (sub_live_...) instead of one shared credential — a compromised key for one integration doesn't require rotating every key across your organization. If you're managing several apps or a team on shared Claude access, see /docs/quickstart for how key scoping works in practice.
Rotate Keys on a Schedule, Not Just After an Incident
Rotation shouldn't be a reactive fire drill. Build it into your operational rhythm:
- Rotate high-privilege keys every 90 days as a baseline.
- Rotate immediately after an employee or contractor with access leaves.
- Rotate immediately if a key appears in logs, error messages, or a client-side bundle by mistake.
- Automate rotation where possible — many secrets managers support scheduled rotation with zero downtime by issuing a new key before revoking the old one.
A rotation that requires a deploy and causes an outage is a rotation people will avoid. Design your key-loading logic so a new key can be swapped in via environment variable or secrets manager update without a code change.
Never Expose Keys Client-Side
Any API key sent to a browser or embedded in a mobile app binary can be extracted. This includes keys in JavaScript bundles, in query strings, or in mobile app decompilation.
If you need to call an API from a frontend, put a thin backend proxy in between:
// Backend route — key stays server-side
app.post("/api/chat", async (req, res) => {
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(req.body)
});
const data = await response.json();
res.json(data);
});
The frontend calls your own /api/chat endpoint, never the upstream provider directly. This also gives you a place to enforce rate limits, log usage, and add authentication for your own users.
Set Up Usage Monitoring and Alerts
A key best practice that's easy to skip until something goes wrong: know what "normal" usage looks like so you can spot abnormal usage. Sudden spikes in request volume, unfamiliar IP ranges, or unusual error rates are early signs of a leaked or misused key.
If your provider exposes usage metadata, check it regularly rather than only when the bill arrives. SubToAPI surfaces per-key request counts and token usage in the dashboard, which makes it straightforward to catch a key behaving unexpectedly before it turns into a large bill or a security incident. Combine that with your own application logs and, if available, IP allowlisting for sensitive server-to-server integrations.
Use Different Keys for Different Purposes
Resist the temptation to reuse one key everywhere because it's convenient. Separate keys for:
- Local development vs. staging vs. production
- Each team or product line, if you have multiple
- CI/CD pipelines vs. running applications
This isolation means a single compromised or misbehaving key has a contained blast radius, and you can see exactly which system is generating which traffic. See /docs/messages for request-level detail if you're setting this up against Claude through SubToAPI, and /pricing if you're deciding how to structure seats across a team.
A Quick Checklist
- [ ] Keys are in environment variables or a secrets manager, never in code
- [ ]
.gitignorecovers all secret files - [ ] Keys are scoped per app/environment/team
- [ ] Rotation is scheduled, not just reactive
- [ ] No key is ever sent to a browser or client app
- [ ] Usage is monitored, with alerts for anomalies
- [ ] Revocation is fast and doesn't require a full deploy
FAQ
How often should I rotate API keys? As a baseline, every 90 days for sensitive keys, plus immediately after any suspected leak or personnel change with access to the key.
Is it safe to store API keys in environment variables? Yes for runtime use, but the source of truth should be a secrets manager with access logs — environment variables alone don't give you audit history or controlled rotation.
What should I do if an API key is leaked? Revoke it immediately, issue a new one, and check usage logs for unauthorized activity during the exposure window. Don't rely on removing it from git history — assume it's already been seen.