REST API Authentication Methods
A partner script scrapes your API with a leaked key. A mobile build ships a password in every header. A "Sign in with GitHub" button works until someone treats the access token as proof of who the user is. Authentication is not one checkbox — it is matching a credential type to a caller and a threat model.
This article is the REST wire-format guide: API keys, Basic Auth, Bearer tokens, JWTs, OAuth 2.0, OpenID Connect, HMAC signatures, and mutual TLS — how each request proves something and where it fails. For when to prefer sessions vs JWTs vs OAuth as models, see JWT vs Session vs OAuth. For JWT claim validation, see JWT deep dive. For IDOR and rate limits after auth, see API security.
Skimmer: which method fits?
API keys and HMAC signatures are usually machine-client patterns. Basic Auth is the old HTTP-native username/password shape. Bearer tokens and JWTs are token-carrying request formats after some login or token exchange. OAuth 2.0 delegates API access through an authorization server. OpenID Connect adds identity on top of OAuth. mTLS authenticates clients at the TLS layer with certificates.
Decision order: human using your app → Bearer token, JWT, OAuth, or OIDC. Machine you trust → API key, HMAC, or mTLS. Prototype only → Basic over HTTPS, then replace. Always return clear 401 vs 403 shapes so clients know whether to re-auth or give up.
Quick reference
- Basic — Authorization: Basic … ; credentials every request.
- Bearer — Authorization: Bearer … ; whoever holds the token can present it.
- JWT — signed Bearer token with claims the API verifies locally.
- OAuth — redirects + code exchange; scopes on the access token.
- OIDC — OAuth 2.0 plus identity via an ID token and UserInfo.
- API key — X-API-Key or similar; rotate and scope per client.
- HMAC/mTLS — stronger machine-to-machine proof, but higher operational cost.
- TLS is mandatory for all header-based methods — headers are visible without it.
Remember this
Basic, Bearer, OAuth, and API keys solve different caller/risk combinations — swapping one in for another changes what a compromised credential can do.
Basic Authentication
Basic Authentication is the simplest HTTP-native approach. The client requests a protected resource; the server may respond with 401 and a WWW-Authenticate challenge; the client retries with Authorization: Basic plus Base64(username:password).
There is no token exchange. Credentials travel on every request. Base64 is encoding, not encryption — without TLS they are effectively plaintext. Even with TLS, logging the Authorization header leaks passwords. Prefer tokens or OAuth for anything user-facing.
Quick reference
- Flow: request → 401 challenge → send username/password → resource.
- Suitable for quick prototypes, VPN-only tools, or legacy clients.
- Never ship to public clients without TLS and a replacement plan.
- Prefer token or OAuth flows for user-facing APIs.
Remember this
Basic Auth is easy to implement but risky for production — treat it as temporary.
Token Authentication
Token authentication separates login from later calls. The client authenticates once; the server returns a token (opaque ID looked up server-side, or a signed JWT). The client sends Authorization: Bearer <token> on each API call so the password is not re-sent.
This fits SPAs and mobile apps. JWTs are stateless but harder to revoke — pair short expiry with refresh tokens. Store tokens in httpOnly cookies (web) or a secure store (mobile), not localStorage when you can avoid it. Validate signature, expiry, and audience on every protected route.
Quick reference
- Best for SPAs, mobile, and any client that can store a token securely.
- Opaque tokens need a session/store lookup; JWTs verify locally.
- Always check signature, exp, and aud — see JWT deep dive.
- Short-lived access + refresh reduces steal-and-reuse windows.
Remember this
Token Auth is the default for modern clients after initial login.
OAuth Authentication
OAuth is designed for delegated authorization — a user grants your app limited access to data on another service without sharing their password. Parties: client app, user, authorization server, and resource server. After consent, the client presents an access token to the API.
Your app never sees the user's Google or GitHub password. Use Authorization Code with PKCE for public clients. Distinguish authorization (OAuth scopes) from authentication (OIDC ID tokens). The resource server must validate issuer, signature, and scopes. Deeper model trade-offs: JWT vs Session vs OAuth.
Quick reference
- Ideal for external IdPs and third-party integrations.
- Authorization Code + PKCE for SPAs/mobile — never Implicit for new apps.
- Validate iss, aud, exp (and nonce for OIDC) before trusting identity.
- Resource server enforces scopes on every request.
Remember this
Choose OAuth when users sign in through a third party or apps need scoped external access.
API Key Authentication
API key authentication is the straightforward machine-to-machine pattern. The server issues a key; the client sends it on later requests — often X-API-Key or a query parameter (prefer headers). The server looks up the key, checks it is active, and authorizes.
Keys are long-lived shared secrets. They fit internal jobs, partner integrations, and small projects where full OAuth is overkill. They are a poor fit for end-user apps: a leaked key grants broad access until rotated. Combine with rate limits and per-key scopes; never embed keys in mobile or frontend bundles.
Quick reference
- Good for cron, ETL, partner server-to-server, and low-risk internal tools.
- Never commit keys; load from a secrets manager.
- Support dual keys during rotation windows.
- Scope and rate-limit per key to limit blast radius.
Remember this
API keys fit machine clients — not end-user authentication.
Bearer Tokens
A Bearer token is a possession credential: the request is accepted because the caller presents a token in Authorization: Bearer <token>. The word Bearer is important. The API is not proving that the original user is still present; it is accepting whoever currently holds that token.
Bearer is a transport shape, not a token format. The token may be opaque and looked up server-side, or it may be a JWT verified locally. Use short expiry, TLS, secure storage, refresh rules, and token revocation where the risk requires it.
Quick reference
- Bearer means possession is enough; stolen tokens are usable until expiry or revocation.
- Opaque Bearer tokens require lookup; JWT Bearer tokens can be signature-verified.
- Never put Bearer tokens in URLs because logs and browser history can leak them.
- Use
401for missing/invalid token and403for valid token without permission. - For browser apps, prefer httpOnly secure cookies when that fits your architecture.
Remember this
Bearer is a possession rule: protect storage and lifetime because the API trusts whoever presents the token.
JSON Web Tokens
A JWT is a signed JSON token, commonly carried as a Bearer token. The API verifies the signature and claims such as issuer, audience, expiry, and subject. That avoids a database lookup on every request, which is why JWTs are popular for distributed APIs.
The trade-off is revocation and correctness. A valid signature only proves the token was issued by a trusted signer and has not been changed. It does not prove the user still exists, the account is active, or the role was not revoked after issuance. Keep access tokens short-lived and re-check sensitive authorization against durable state when needed.
Quick reference
- JWTs are self-contained and signed; they are not automatically encrypted.
- Always verify signature, issuer, audience, expiry, and key ID handling.
- Use short-lived access tokens when roles or access can change quickly.
- Do not store secrets or private profile data in a readable JWT payload.
- Pair with refresh tokens or sessions when user-facing login needs renewal.
Remember this
A JWT removes per-request lookup only if every API verifies the signature and claims correctly.
OpenID Connect
OpenID Connect, or OIDC, is the identity layer on top of OAuth 2.0. OAuth answers “can this client access this API with these scopes?” OIDC adds an ID token and discovery conventions so the client can learn who signed in. The access token is for the API; the ID token is for the client to understand the user identity.
This distinction prevents a common bug: treating an OAuth access token as proof of login. A resource server validates access tokens and scopes. A client validates the ID token issuer, audience, nonce, expiry, and signature before creating a local session or personalizing the UI.
Quick reference
- Use OIDC for sign-in and SSO; use OAuth scopes for API access.
- ID tokens are intended for the client, not as generic API credentials.
- Validate nonce to bind the login response to the request that started it.
- Use provider discovery metadata for issuer, JWKS, and endpoints.
- Map external identity to local roles with explicit authorization rules.
Remember this
OIDC proves identity to the client; OAuth access tokens authorize API calls.
HMAC Signature Authentication
HMAC authentication signs the request with a shared secret instead of sending the secret itself. The client builds a canonical string from method, path, timestamp, body hash, and selected headers, then sends the signature. The server rebuilds the same string and compares signatures. If any signed part changes, verification fails.
This pattern is useful for server-to-server APIs and webhooks because it can prove integrity and reduce replay risk. It is also easy to get wrong: both sides must canonicalize exactly the same way, clocks must be bounded, and secrets still need rotation. Use constant-time comparison and include a timestamp or nonce.
Quick reference
- Signs the request; the shared secret is not sent on the wire.
- Protects integrity of signed fields and body hash.
- Timestamp or nonce prevents replay within the accepted time window.
- Canonicalization bugs cause false rejects or signature bypasses.
- Great for webhooks and service calls; too complex for browser clients.
Remember this
HMAC proves the request was signed with a shared secret and was not changed after signing.
Mutual TLS
Mutual TLS authenticates both sides during the TLS handshake. The server presents its certificate as usual, and the client also presents a certificate issued by a trusted authority. The server verifies the client certificate before application code handles the request.
mTLS is strongest when service identity belongs at the network boundary: internal service mesh traffic, banking or partner APIs, and high-trust machine-to-machine integrations. It is not a replacement for application authorization. After the certificate proves the client service, the API still checks whether that service can perform the requested action.
Quick reference
- Authentication happens before HTTP handlers run.
- Works well for service-to-service traffic with managed certificates.
- Certificate issuance, rotation, revocation, and trust stores are operational work.
- Still pair with API authorization, scopes, or service policy.
- Usually overkill for public browser or mobile clients.
Remember this
mTLS proves service identity at the transport layer; application policy still decides allowed actions.
Which method should you use?
The methods solve different proof problems. Basic sends a password-like credential. API keys identify a machine client. Bearer tokens prove possession. JWTs prove signed claims. OAuth delegates scoped access. OIDC proves identity to the client. HMAC proves request integrity. mTLS proves client service identity during TLS.
Most production systems combine them: OAuth/OIDC for sign-in, Bearer JWTs for your own API, API keys or HMAC for partners and webhooks, and mTLS for service-to-service traffic where certificate operations are worth the cost. Goal: least privilege — each client gets the narrowest credential and scope it needs. Pair with API security for authorization after the credential is accepted.
Quick reference
- User-facing app you control → Token (JWT + refresh) or OAuth/OIDC.
- Sign in with Google/GitHub/enterprise SSO → OAuth 2.0 + OIDC.
- Internal cron or ETL → API key, HMAC, or OAuth client credentials.
- Webhooks → HMAC signature with timestamp/nonce and replay protection.
- Service mesh or high-trust partner link → mTLS plus application authorization.
- Quick prototype → Basic over HTTPS only, then replace.
- Match credential type to client and risk — do not force one method everywhere.
Remember this
Pick the method that matches who is calling — human, your app, or another service.
Key takeaway
REST authentication is a set of wire contracts, not one universal best practice. Basic trades safety for simplicity. API keys keep machine access lightweight. Bearer tokens carry possession. JWTs carry signed claims. OAuth delegates access. OIDC proves identity. HMAC signs request integrity. mTLS proves service identity before HTTP handlers run.
Practice (30 min): For one endpoint, pick the credential type and write curl for the happy path plus JSON bodies for 401, 403, and replay/expiry failure. Then state what is proven: possession, signature, delegated scope, user identity, request integrity, or client certificate identity. Pass when you can explain why a valid credential may still receive 403.
Related Articles
Explore this topic