What a key identifies
A key normally identifies an application or project, not a person. Everyone using your app sends the same key from your server, and the provider sees one customer. That is exactly what a key is good at: metering usage, applying a rate limit, sending the bill, and switching off one misbehaving integration without affecting the rest.
It also sets the limit of what a key can do. A key cannot say which user of your app a request is for, and it never expires unless somebody revokes it. When an app needs to act for individual users, with their consent and for a limited time, the tool is OAuth and its access tokens, not a key.
Many providers build structure into the string. A prefix such as sk_live_ or
ghp_ says which service and which kind of key it is, which lets secret scanners recognise a
leaked one in public code. Some issue the key in two halves: a public identifier that may appear in a
browser, and a secret that must stay on a server.
Where the key goes in a request
There is no standard for this, so every provider chooses, and sending a valid key in the wrong place is answered exactly like sending no key. The four forms in use:
| Form | Example | Notes |
|---|---|---|
| Bearer token | Authorization: Bearer sk_live_9f2c… | The most common today. See bearer tokens. |
| Custom header | X-API-Key: 9f2c41… | The header name varies by provider: x-api-key, x-goog-api-key, apikey. |
| Query parameter | GET /v1/geocode?key=9f2c41… | Easy to test, but URLs are written to access logs, proxies and browser history. |
| Basic auth username | Authorization: Basic OWYyYzQxOg== | The key as the username with an empty password, Base64-encoded. |
Prefer a header whenever the provider offers the choice. A header is not recorded by default in server
logs and is not passed on in a Referer; a query string is both. The
Authorization header guide covers the syntax, and the
curl bearer token example shows the command-line form.
API key, access token and JWT
| API key | OAuth access token | JWT | |
|---|---|---|---|
| Identifies | An application | An application acting for a user | Whatever its claims say |
| Lifetime | Until revoked | Minutes to hours, then refreshed | Until its exp claim |
| Obtained by | Copying from a dashboard | An OAuth flow | Signing, by whoever issues it |
| Checked by | A database lookup | A lookup, or by verifying a signature | Verifying the signature |
| Readable | No, it is random | Depends on the provider | Yes, with a JWT decoder |
The three are often sent the same way, after the word Bearer, which is why they get
confused. A JWT is a format, and an access token may or may not be one;
OAuth vs JWT untangles that pair.
Keeping a key safe
- Keep secret keys on a server. Anything shipped to a browser or inside a mobile app can be extracted by its user. If a front end needs an API, route the call through your own back end and add the key there.
- Keep keys out of source control. Read them from an environment variable or a
secrets manager, and add the local file that holds them to
.gitignorebefore the first commit. Deleting a committed key in a later commit does not remove it from the history. - Give each environment and each service its own key. One key shared by production, staging and three laptops cannot be revoked without breaking all of them, and its usage cannot be told apart.
- Restrict what each key can do. Where the provider allows it, limit a key to the endpoints it needs, to read-only access, or to your servers' IP addresses. A restricted key that leaks is an inconvenience; an unrestricted one is an incident.
- Rotate on a schedule and whenever someone leaves. Rotation is easy if two keys can be valid at once: issue the new one, deploy it, then revoke the old one.
- Send keys only over HTTPS. Over plain HTTP, every network between you and the provider can read the header. See HTTP vs HTTPS.
If a key leaks
Revoke it first and investigate afterwards. Create a replacement, deploy it, delete the exposed key, and only then look at the provider's usage log to see whether anyone else used it. Automated scanners find keys pushed to public repositories within minutes, so a key that was public even briefly should be treated as used.
Testing whether a key works
Send the cheapest authenticated read the provider offers, such as a list-models or account endpoint, and
read the status code. 200 means the key is valid.
401 means the key was missing, malformed or not recognised.
403 means the key is valid but not allowed to do this, or is
restricted to an address you are not calling from. 429 means it
is valid and over a limit.
The API key tester does this for any provider, and there are pre-filled consoles for OpenAI, Anthropic, Gemini, DeepSeek, Stripe and others. Each relays the request through this site's server, so use a test or restricted key there rather than an unrestricted production one.
Generating keys for your own API
If you are the one issuing keys, four rules cover most of it.
- Use a cryptographic random source and at least 128 bits of randomness; 32 random bytes, written as hex or Base64url, is a common choice. A general-purpose random function or a timestamp is guessable. The random string generator on this site uses the browser's cryptographic source and is suitable for making a test key.
- Store a hash, not the key. Save a SHA-256 hash and compare hashes on each request, so a copy of your database is not a copy of every customer's key. Because the key is long and random, a fast hash is sufficient here, unlike for passwords. The hash generator shows what is stored.
- Show the key once. Display it at creation and never again. Keep the first few characters in clear so a customer can tell their keys apart in a list.
- Add a prefix. A short fixed prefix identifies your service and the key type, and lets code-hosting platforms' secret scanning detect your keys when they are committed by mistake.
References
- OWASP API Security Top 10: Broken Authentication — How API credentials are attacked, and the defences that matter.
- OWASP Secrets Management Cheat Sheet — Storing, rotating and auditing keys and other secrets.
- RFC 6750: Bearer Token Usage — The Authorization: Bearer scheme most APIs use to carry a key or token.
These links leave api-tester.com, which is independent of the organisations they point to.
Frequently asked questions
What is an API key used for?
To identify the application making a request, so the provider can authorise it, count its usage, apply rate limits and bill for it. It identifies the calling program rather than an individual user.
Is an API key the same as a password?
It plays the same role for software, but it is long, random and issued by the provider, and it is sent on every request instead of once at login. It should be stored and protected as carefully as a password.
Where do I put an API key in a request?
Wherever that provider's documentation says. The usual places are an Authorization header with the Bearer scheme, a custom header such as X-API-Key, a query parameter, or the username of HTTP Basic authentication. Prefer a header to a query parameter when both are offered.
Is it safe to put an API key in front-end code?
Not a secret one. Anything sent to a browser or bundled into a mobile app can be read by the person using it. Call the API from your own server instead, or use a key the provider designed to be public and restricted by domain.
What should I do if my API key is leaked?
Revoke it immediately and issue a new one, then check the provider's usage logs for calls you did not make. Removing the key from a file or a later commit is not enough, because copies remain in history and in anything that already read it.
How long should an API key be?
Long enough that guessing is impossible: at least 128 bits of randomness from a cryptographic source. Thirty-two random bytes encoded as 64 hex characters or 43 Base64url characters is a common and comfortable size.