Your API key is a bearer credential: whoever holds it can spend your credits. There is no second factor on an API call and no per-request signature — that is the trade for an integration you can finish in five minutes, and it makes key handling the whole of your security posture here.
This page is what to do about that, in the order it matters.
Keep the key out of everything
Environment variables or a secrets manager. Nothing else.
const key = process.env.APIVERVE_API_KEY; // yes
const key = 'apv_9f3c…'; // noThe list of places a key must not be, in rough order of how often each one actually happens:
- A repository. Including a config file you meant to gitignore, and including the git history after you delete it.
- Client-side code. Anything in a browser bundle, a mobile app or a desktop app is readable by anyone who has it. Minification is not protection.
- A URL. Anything in a URL is logged by proxies, CDNs and browsers, and ends up in referrer headers. The key belongs in a credential store, which is the only place it is designed to be.
- Logs. Redact the credential before you log anything carrying it. A log aggregator with a key in it is a credential with a much wider audience than you intended.
- Support tickets, screenshots and chat. If a key has ever been pasted into one, it is compromised.
If a key does get out, rotate it immediately. Rotation is instant and free; the exposure is not.
Do not call the API from a browser
Any request your front end makes carries a key the user can read. There is no configuration that makes that safe.
Three ways to avoid it:
Proxy through your own backend. Your server holds the key, your front end calls your server. This is the normal answer, and it also gives you a place to cache and rate-limit.
Use an embedded form. For a lookup tool on a page, the form authenticates with a form token and proxies server-side — no key in the page at all, plus a domain allow-list and a CAPTCHA.
Accept the exposure deliberately, and bound it. If a key genuinely must be public — a demo, an internal tool — it should be a sub-key, blocked down to the one call it needs, rate-capped, and rotated on a schedule. See key scoping.
Bound what each key can do
One key everywhere means one incident everywhere. The alternative costs a few minutes:
- A sub-key per consumer — per environment, per client, per job. Each is revocable on its own.
- Scoped to what it calls. Blocking is a deny-list, so a narrow key needs revisiting as the catalog grows.
- IP allow-listed, on Mega, for anything running somewhere you can name.
- Rate-capped, on Mega, for anything bulk — so a runaway job cannot consume the whole allowance.
- Expiring, on paid plans, for anything with an end date.
The measure of this is not whether it prevents a leak — it does not — but what a leaked key is worth. Two endpoints, one address and thirty requests a minute is a bad afternoon. An unrestricted primary key is your account.
What the transport gives you
HTTPS only. Requests are TLS-encrypted end to end, and plain HTTP is not served. Do not disable certificate verification in a client to make something work — that turns the guarantee off entirely and the underlying problem is nearly always a missing CA bundle.
No credentials in a URL. Nothing that authenticates travels in one.
CORS is closed by design on the API itself, which is the mechanism preventing a page from quietly spending someone else's credits. See CORS.
Validate before you send
Two habits that are about your application rather than the API, and both pay for themselves:
Never forward raw user input as a parameter. Validate the shape you expect first. An email field that accepts anything sends anything, and you pay a credit for every piece of nonsense.
Bound what you accept. Length limits on inputs, and a size limit on uploads, before the request goes out. Your plan's max response size is a ceiling on what comes back — see plans — but the request side is yours to bound.
The API validates too, and rejects bad input with a 400 naming the parameter. That is a
correction, not a defence: the call still had to be made, and a validation failure you could have
caught locally is a round trip you paid for in latency.
Watch the account
The 80% usage warning is on by default. Leave it on. A key being used by someone else usually shows up as consumption before it shows up as anything else. See settings.
Read the per-API breakdown occasionally. An endpoint you do not recognise in analytics is the clearest signal there is that a key is being used by something you did not write.
Check the login activity after enabling two-factor, and any time something looks off. Dashboard security and API security are separate — two-factor protects the account, not the key — but a sign-in you do not recognise means both need attention.
On Mega, the audit history records key rotations, sub-key changes and membership changes with who did them, which is what you want during an incident and what a compliance review asks for.
Before you ship
- Key in an environment variable or secrets manager, not in the repository
- No key in any client-side code, URL or log
- A sub-key rather than the primary key for anything that is not your own production system
- Restrictions set on keys that go outside your infrastructure
- Separate keys for staging and production
- Usage alerts on, and someone reading them
- A rotation you have actually rehearsed, not just written down
Next
Authentication covers the header and the failure modes. Key scoping covers restrictions in detail, and error handling covers what each rejection means.
For the abuse arriving at your own front door rather than at your key, block fake signups covers screening registrations, and CORS covers why a key never belongs in a page.