API Authentication Methods: API Keys, JWT, OAuth 2.0 Explained
Compare the main API authentication methods — API keys, JWT, OAuth 2.0, and session cookies — and learn when to use each one in your applications.
By Belqassim Djafer · Published · Updated
Why API Authentication Matters
Every API that serves private data or triggers actions must verify the identity of the caller. Poor authentication is consistently in the OWASP Top 10 and is the cause of most significant data breaches. Understanding when to use each authentication method — and how to implement it correctly — is a core skill for every developer who builds or consumes APIs.
API Keys
The simplest authentication mechanism: a random token generated by the server and given to the client.
GET /api/data HTTP/1.1
Host: api.example.com
Authorization: Bearer sk_live_1234abcd5678efgh
Or as a query parameter (less secure, appears in logs):
GET /api/data?api_key=sk_live_1234abcd5678efgh
When to Use API Keys
- Machine-to-machine communication between servers
- Public APIs where users register for access
- Simple access control without user identity requirements (the key identifies an app, not a person)
- Stripe, SendGrid, Google Maps, OpenAI all use API keys
Security Best Practices
// Always pass in headers, never in URLs
const response = await fetch("https://api.example.com/data", {
headers: {
"Authorization": `Bearer ${process.env.API_KEY}`, // From env, not hardcoded
}
});
- Store in environment variables, never in source code
- Rotate keys periodically and immediately upon suspected exposure
- Restrict keys by IP address or scope when the provider allows it
- Use different keys per environment (dev, staging, production)
JWT (JSON Web Tokens)
JWT is a compact, self-contained token format that encodes claims (user identity, roles, expiry) as a signed JSON payload.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4iLCJpYXQiOjE1MTYyMzkwMjJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The three base64url-encoded parts are:
- Header: algorithm and type
- Payload: claims (user ID, roles, expiry)
- Signature: HMAC or RSA signature for verification
// Decoded payload
{
"sub": "user_123",
"name": "Alice",
"roles": ["admin"],
"iat": 1716000000,
"exp": 1716086400
}
JWT Authentication Flow
1. User logs in with username/password
2. Server validates credentials, generates JWT signed with secret key
3. Server returns JWT to client
4. Client stores JWT (memory or httpOnly cookie)
5. Client sends JWT in Authorization header for subsequent requests
6. Server validates signature without database lookup (stateless)
When to Use JWT
- Stateless APIs: the server doesn't need to store session data
- Microservices: tokens can be validated by any service that has the public key
- Short-lived access tokens (15 min) paired with long-lived refresh tokens
JWT Security Pitfalls
// Never use algorithm "none" — it disables signature verification
// Never trust the "alg" field in the header
// Always verify the signature with the correct key
// Always validate exp (expiry)
import jwt from "jsonwebtoken";
// Correct: specify allowed algorithms explicitly
const payload = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ["HS256"], // Explicitly allow only HS256
issuer: "api.example.com", // Validate issuer
audience: "app.example.com" // Validate audience
});
Access Tokens + Refresh Tokens
Access token: short-lived (15 min), stored in memory
Refresh token: long-lived (7–30 days), stored in httpOnly cookie
Flow:
1. Auth: returns access + refresh token
2. API call with access token
3. Access token expires → use refresh token to get new access token
4. Refresh token expires → user must log in again
OAuth 2.0
OAuth 2.0 is an authorisation framework that allows a user to grant a third-party application limited access to their resources without sharing their password.
The 4 OAuth 2.0 Grant Types
| Grant Type | Use Case |
|---|---|
| Authorization Code | Web apps with a server side (most secure) |
| Authorization Code + PKCE | SPAs and mobile apps |
| Client Credentials | Server-to-server (no user involved) |
| Device Code | Smart TVs, CLI tools |
Authorization Code Flow (simplified)
1. Your app redirects user to OAuth provider:
https://github.com/login/oauth/authorize?
client_id=abc&
redirect_uri=https://app.example.com/callback&
scope=read:user&
state=random_csrf_token
2. User authenticates at GitHub, approves scopes
3. GitHub redirects back with: ?code=TEMP_CODE&state=random_csrf_token
4. Your server exchanges code for access token (server-to-server):
POST https://github.com/login/oauth/access_token
client_id, client_secret, code
5. Response: { access_token: "gho_...", token_type: "bearer" }
6. Use access token to call GitHub API on behalf of user
When to Use OAuth 2.0
- "Login with Google/GitHub/etc." in your app
- Accessing a user's data from another service (read their calendar, post to their social media)
- When you need fine-grained permission scopes
Session Cookies (Traditional)
1. User logs in → server creates session in database
2. Server sends Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax
3. Browser automatically sends cookie with every request to same origin
4. Server looks up session in database to identify user
Best for: traditional web applications with a single server, where you need immediate session revocation (logout).
Comparison
| Method | Stateless | User Identity | Revocable | Best For |
|---|---|---|---|---|
| API Key | ✅ | App/service | Manual key rotation | M2M, public APIs |
| JWT | ✅ | User + claims | Not until expiry | Stateless APIs, microservices |
| OAuth 2.0 | ✅ | User (via provider) | Via token endpoint | Third-party auth, social login |
| Session Cookie | ❌ DB lookup | User | Immediately | Traditional web apps |
Use our JWT Decoder to inspect JWT tokens and understand their claims without needing to write code.
Conclusion
No single authentication method is universally best. API keys are simple and reliable for M2M scenarios. JWT enables stateless, distributed authentication. OAuth 2.0 handles delegated user access. Session cookies provide immediate revocability for traditional apps. The most secure implementations use HTTPS everywhere, short token lifetimes, and the principle of least privilege.