API Key Management: Practices That Actually Scale
API key management is the set of practices you use to create, distribute, rotate, scope, and revoke the credentials that let software talk to your APIs. Done well, it means a leaked key does limited damage, you know exactly who used what and when, and rotating a key never turns into a production incident. Done badly, it means shared .env files floating around Slack, keys hardcoded in client-side JavaScript, and no idea which key belongs to which service when something breaks.
If you're searching for this because you just found a key committed to a public repo, or because your team is growing and "one key for everyone" isn't working anymore, this article covers the concrete practices that matter: scoping, storage, rotation, monitoring, and the tooling patterns that make all of it sustainable instead of a recurring fire drill.
Why API key management gets messy
Most teams start with a single API key. It works fine until:
- Multiple services need access, and you can't tell which one is making which calls
- Someone leaves the team and you have no idea what keys they had access to
- A key leaks (client-side code, a public repo, a log file) and you have to decide whether to rotate it — and rotating means updating every place it's used
- You want usage limits per service or per customer, but the key has none
- Billing or usage attribution becomes a guessing game across teams
None of these are exotic problems. They're the default outcome of treating API keys as static secrets instead of managed, auditable objects.
Core practices for managing API keys
1. One key per consumer, not per team
The single biggest improvement most teams can make is issuing a distinct key for every service, environment, and integration — not one shared key for "the backend." A key per consumer means:
- You can revoke one integration without breaking others
- Usage and cost attribution is automatic
- A leak is contained to whatever that specific key could do
If you're consuming a third-party API (including one built with SubToAPI), generate separate keys for staging vs. production, and for each distinct service that calls it, rather than reusing one key everywhere.
2. Scope keys to the minimum they need
Not every key needs full access. If your API or provider supports scoping — read-only vs. write, specific endpoints, specific rate limits — use it. A key used only for a reporting dashboard shouldn't be able to trigger destructive actions elsewhere in your system.
3. Never put keys in client-side code
API keys belong on your server, not in a browser bundle or mobile app binary. Any key shipped to a client can be extracted. If you need to expose functionality to a frontend, put a thin backend in front of the real API key:
// server.js — the browser never sees the real key
app.post("/api/proxy-endpoint", async (req, res) => {
const response = await fetch("https://api.example.com/v1/resource", {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
method: "POST",
body: JSON.stringify(req.body),
});
const data = await response.json();
res.json(data);
});
This applies whether the upstream API is your own or a third party's, including something like a SubToAPI application key — the pattern is identical: keep SUBTOAPI_KEY server-side, expose a scoped endpoint to your frontend.
4. Store keys as secrets, not as code
Keys should live in environment variables or a secrets manager (Vault, AWS Secrets Manager, Doppler, or your platform's built-in secret store), never in source control. A basic .gitignore entry for .env is table stakes, not a solution — assume any key that ever touched a git history is compromised and rotate it.
# .env — never committed
SUBTOAPI_KEY=sub_live_xxxxxxxxxxxxxxxx
DATABASE_URL=postgres://...
5. Rotate keys on a schedule, not just after an incident
Rotation shouldn't be a reactive, panicked process. Build it into your operations:
- Set an expectation (e.g., rotate every 90 days) even if nothing has gone wrong
- Support having two valid keys simultaneously during a rotation window, so you can update consumers without downtime
- Automate rotation where your provider's API allows it, rather than doing it manually through a dashboard every time
6. Monitor usage per key
You can't manage what you can't see. Track requests, errors, and volume per key, and set alerts for anomalies — a sudden spike from a key that normally makes ten requests a day is worth investigating immediately, not at the end of the month. This is also how you catch a leaked key before it turns into a large bill or a security incident.
7. Revoke immediately, don't wait
If a key is suspected compromised — appeared in a log, was pasted into a public forum, an employee with access left — revoke it immediately and issue a replacement. The cost of over-reacting (a few minutes updating a config) is far lower than the cost of under-reacting.
Applying this to LLM API access
These practices matter just as much when the API in question wraps a model provider. If you're giving your team or your product programmatic access to Claude, you want the same discipline: per-application keys, usage visibility, and easy rotation, without every developer needing direct access to a shared account.
This is the specific problem SubToAPI (https://subtoapi.app) is built around. It turns your existing Claude access into a proper HTTPS API with scoped application keys (sub_live_...), streaming, tool use, and usage metadata per key, so you can issue a distinct key to each service or teammate instead of sharing one credential across your whole team. Team and Scale plans add seat-based access so you can manage who has keys without giving everyone the same level of access. See /pricing for plan details, or /docs/quickstart to get a key running in a few minutes.
A minimal request once you have a key looks like this:
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4",
"messages": [{"role": "user", "content": "Summarize this in one sentence."}]
}'
Full request and response formats are in /docs/messages, and streaming setup is covered in /docs/streaming if your application needs incremental responses rather than waiting for the full completion.
A practical checklist
- Issue one key per service/environment, not one shared key
- Keep keys server-side; never ship them in client code
- Store keys in environment variables or a secrets manager, never in git
- Rotate keys on a schedule and support overlapping validity during rotation
- Monitor usage per key and alert on anomalies
- Revoke suspected-compromised keys immediately, no exceptions
questions
How often should I rotate API keys? There's no universal number, but 90 days is a common baseline for keys with broad access. Low-risk, narrowly scoped keys can go longer; anything tied to production infrastructure or billing should rotate more frequently or be automated.
What should I do if an API key leaks into a public repo? Revoke it immediately, even before you've fully confirmed misuse — assume it's compromised the moment it's visible. Issue a replacement key, update all consumers, and scrub the key from git history if possible, though revocation is what actually stops the exposure.
Can I use the same API key across multiple environments? You can, but you shouldn't. Separate keys per environment (development, staging, production) let you revoke or rate-limit one without affecting the others, and make it obvious in your logs which environment generated any given request.