REST API Authentication
Secure your APIs with OAuth 2.0, JWT, API Keys, and industry-standard authentication methods
Authentication Overview
Authentication verifies the identity of clients accessing your API. Choosing the right method depends on your use case, security requirements, and client types. Failed authentication should return proper status codes like 401 or 403.
- API Keys — Simple, best for server-to-server
- OAuth 2.0 — Industry standard for third-party access
- JWT — Stateless, self-contained tokens
- Bearer Tokens — Flexible token-based auth
- Basic Auth — Simple but limited security
Authorization: Bearer eyJhbGciOiJIUzI1...
{
"status": "authenticated",
"user": "john@example.com"
}
API Keys
API keys are unique identifiers used to authenticate requests. They're simple to implement and ideal for server-to-server communication.
Header-Based (Recommended)
Send API key in a custom header. More secure as it's not logged in URLs or browser history.
X-API-Key: your_api_key_here
Authorization: ApiKey your_key
Query Parameter (Less Secure)
API key in URL. Avoid when possible — keys appear in logs, browser history, and referrer headers.
/api/data?api_key=your_key
⚠️ Visible in server logs
🔑 API Key Best Practices
Use HTTPS always
Rotate keys periodically
Scope keys to specific permissions
Embed keys in client-side code
Share keys across environments
📋 Implementation Example
// Server-side validation
const apiKey = req.headers['x-api-key'];
if (!apiKey) {
return res.status(401).json({
error: 'API key required'
});
}
const isValid = await validateApiKey(apiKey);
if (!isValid) {
return res.status(403).json({
error: 'Invalid API key'
});
}
OAuth 2.0
OAuth 2.0 is the industry-standard protocol for authorization. It enables third-party applications to obtain limited access to user accounts.
Authorization Code Flow
Most secure flow for server-side apps. Exchanges auth code for tokens via backend.
Best for: Web applications with backendsClient Credentials
Machine-to-machine authentication. Client exchanges credentials directly for tokens.
Best for: Server-to-server APIs, microservicesPKCE Extension
Proof Key for Code Exchange. Protects authorization code from interception.
Best for: Mobile apps, SPAs, public clientsImplicit Flow (Deprecated)
Returns tokens directly in URL. Vulnerable to token leakage. Use PKCE instead.
Status: DeprecatedAuthorization Code Flow Diagram
┌──────────┐ ┌──────────────┐
│ User │ │ Auth Server │
└────┬─────┘ └──────┬───────┘
│ │
│ 1. Click "Login with Provider" │
│ ─────────────────────────────────────────>│
│ │
│ 2. Redirect to authorization URL │
│ <─────────────────────────────────────────│
│ │
│ 3. User authenticates & grants consent │
│ ─────────────────────────────────────────>│
│ │
│ 4. Redirect with authorization code │
│ <─────────────────────────────────────────│
│ │
┌────┴─────┐ │
│ Client │ 5. Exchange code for tokens │
│ Server │ ───────────────────────────────────>│
└────┬─────┘ │
│ 6. Return access_token + refresh_token │
│ <─────────────────────────────────────────│
│ │
│ 7. Access protected resources │
│ ─────────────────────────────────────────>│
▼ ▼
📝 Authorization Request
GET /oauth/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://app.com/callback
&scope=read write
&state=xyz123
&code_challenge=E9Melhoa2OwvFrEMTJg...
&code_challenge_method=S256
🎫 Token Exchange
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE_HERE
&redirect_uri=https://app.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_SECRET
&code_verifier=original_verifier
JWT (JSON Web Tokens)
JWTs are self-contained tokens that securely transmit information as a JSON object. They're digitally signed and can be verified without database lookups.
JWT Structure
A JWT consists of three parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6....SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV...
- ■ Header — Algorithm & token type
- ■ Payload — Claims (user data)
- ■ Signature — Verification hash
Decoded Payload
{
"iss": "api.example.com",
"sub": "user_123",
"iat": 1704067200,
"exp": 1704153600,
"name": "John Doe",
"role": "admin"
}
Standard Claims
Validation Steps
Refresh Token Pattern
┌─────────────────────────────────────────────────────────────────┐
│ Access + Refresh Token Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Login ──────> Server returns: │
│ • access_token (short-lived: 15min-1hr) │
│ • refresh_token (long-lived: days-weeks) │
│ │
│ 2. API calls ──> Use access_token in Authorization header │
│ │
│ 3. Token expires ──> Access token returns 401 │
│ │
│ 4. Refresh ────> POST /auth/refresh with refresh_token │
│ Server returns new access_token │
│ │
│ 5. Logout ─────> Invalidate refresh_token on server │
│ │
└─────────────────────────────────────────────────────────────────┘
POST /auth/refresh
{
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..."
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 3600
}
Bearer Tokens
Bearer tokens are access tokens sent in the Authorization header. Anyone "bearing" the token can use it, so secure transmission is critical.
Authorization Header
The standard way to send bearer tokens. Supported by all HTTP clients and frameworks.
Authorization: Bearer <token>
GET /api/v1/users HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
Token Storage Best Practices
Where you store tokens affects security. Choose based on your client type.
HttpOnly cookies (prevents XSS)
Secure keychain/keystore
Environment variables
localStorage (vulnerable to XSS)
URL parameters
🔒 Security Checklist
Always HTTPS
Never transmit tokens over unencrypted connections
Short Expiration
Access tokens should expire in 15 minutes to 1 hour
Token Rotation
Issue new refresh tokens on each use
Revocation
Implement token blacklisting for logout/security events
Basic Authentication
Basic auth sends credentials encoded in Base64. Simple but only secure over HTTPS. Best for internal APIs and development.
How It Works
- Combine username and password:
user:password - Encode with Base64:
dXNlcjpwYXNzd29yZA== - Send in header:
Authorization: Basic dXNlcjpwYXNzd29yZA==
Internal APIs, dev environments, CLI tools
Public APIs, browser clients, production without HTTPS
Example Request
GET /api/v1/users HTTP/1.1
Host: api.example.com
Authorization: Basic dXNlcjpwYXNzd29yZA==
# Decoded: user:password
# ⚠️ Base64 is NOT encryption!
⚠️ Critical Requirements
✅ When Basic Auth Is OK
Comparison & Recommendations
Best For
Server-to-server APIs, rate limiting, usage tracking, simple integrations.
Simple, easy to implement, good for tracking
No user context, hard to rotate at scale
Best For
Third-party integrations, social login, delegated authorization, enterprise apps.
Industry standard, granular scopes, no password sharing
Complex implementation, multiple flows to support
Best For
Stateless APIs, microservices, distributed systems, mobile apps.
No DB lookup, contains user claims, scalable
Can't revoke easily, larger than session IDs