API authentication basics: API keys, Bearer tokens, and OAuth
How APIs know who is calling: static API keys, Bearer tokens in the Authorization header, Basic auth, and a high-level tour of OAuth 2.0, plus how to keep secrets safe.
Not checked by a trusted editor yet Last edited Outdated?
Most APIs need to know who is calling before they answer. The caller proves it by attaching a credential to every request, usually in a header. The main options differ in who issues the credential, how long it lives, and what it is allowed to do.
API keys
An API key is a long random string the provider gives you in a dashboard. You send it with each request, typically in a header the provider names:
curl -H "X-API-Key: $EXAMPLE_API_KEY" https://api.example.com/v1/reports
Keys are simple, which is why they are popular for server-to-server calls. Their weakness is that they usually live until someone revokes them, and they identify an application rather than a user. Some APIs accept keys in the query string, but avoid that when you can: URLs are stored in server logs, proxies, and browser history.
Bearer tokens
A Bearer token goes in the standard Authorization header. Whoever holds (bears) the token gets access, so treat it exactly like a password.
curl -H "Authorization: Bearer $ACCESS_TOKEN" https://api.example.com/v1/me
Tokens are often short-lived and issued after a login or an OAuth flow. Some are opaque random strings the server looks up; others are JWTs, which carry signed claims such as the user ID and expiry time. A JWT’s payload is only Base64URL-encoded, not encrypted, so anyone holding it can read it. Never put secrets inside one.
Basic authentication
Basic auth sends username:password Base64-encoded in the Authorization header. Base64 is an encoding, not encryption, so Basic auth is only acceptable over HTTPS. curl builds the header for you with -u:
curl -u "demo-user:$DEMO_PASSWORD" https://api.example.com/v1/status
OAuth 2.0 in one picture
OAuth lets a user give an app limited access to their account on another service without handing over their password. The typical flow for web and mobile apps is the authorization code flow:
- Your app sends the user to the provider’s login page, listing the scopes (permissions) it wants.
- The user logs in there and approves the request.
- The provider redirects back to your app with a one-time authorization code.
- Your app exchanges that code for an access token (and often a refresh token).
- Your app calls the API with
Authorization: Bearerplus the access token. When it expires, the refresh token gets a new one.
Apps that cannot keep a secret, such as single-page and mobile apps, should add PKCE, which ties the code to the app instance that started the flow. For machine-to-machine calls with no user involved, the client credentials flow swaps a client ID and secret directly for a token. In practice, use a well-maintained OAuth library rather than implementing these steps by hand.
401 versus 403
A 401 Unauthorized means the server does not know who you are: the credential is missing, malformed, or expired. A 403 Forbidden means it knows exactly who you are and you are not allowed to do this. Refreshing a token can fix a 401; only a change of permissions or scopes fixes a 403.
Keeping secrets safe
- Load keys and tokens from environment variables or a secret manager, never from source code.
- Add
.envfiles to.gitignore. If a secret is ever committed, revoke and rotate it; deleting the commit is not enough. - Never ship a private API key in browser JavaScript. Anything sent to the browser can be read. Call the API from your own backend instead.
- Request the smallest scopes you need and prefer short-lived tokens.
- Always use HTTPS, so credentials are encrypted in transit.
See also
- 0083 Test a JSON API with curl A runnable bash script showing the curl commands you need most when testing an API: GET, POST JSON, custom headers, Bearer tokens,… Beginner · How-to · Linux, macOS, Windows Script Authentication · Making requests 15 Oct 2026
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- Commitpedia +3,566 chars