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
GET /api/v1/protected
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

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

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

✅ Do Use HTTPS always
✅ Do Rotate keys periodically
✅ Do Scope keys to specific permissions
❌ Don't Embed keys in client-side code
❌ Don't 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 backends
🖥️

Client Credentials

Machine-to-machine authentication. Client exchanges credentials directly for tokens.

Best for: Server-to-server APIs, microservices
📱

PKCE Extension

Proof Key for Code Exchange. Protects authorization code from interception.

Best for: Mobile apps, SPAs, public clients
⚠️

Implicit Flow (Deprecated)

Returns tokens directly in URL. Vulnerable to token leakage. Use PKCE instead.

Status: Deprecated

Authorization 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

iss Issuer — Who created the token
sub Subject — User/entity identifier
exp Expiration — When token expires (Unix timestamp)
iat Issued At — When token was created
aud Audience — Intended recipient
jti JWT ID — Unique token identifier

Validation Steps

1 Verify signature using secret/public key
2 Check expiration (exp) hasn't passed
3 Validate issuer (iss) is trusted
4 Confirm audience (aud) matches your API
5 Check token isn't blacklisted (optional)

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.

FORMAT

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
STORAGE

Token Storage Best Practices

Where you store tokens affects security. Choose based on your client type.

✅ Web HttpOnly cookies (prevents XSS)
✅ Mobile Secure keychain/keystore
✅ Server Environment variables
❌ Never localStorage (vulnerable to XSS)
❌ Never 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

  1. Combine username and password: user:password
  2. Encode with Base64: dXNlcjpwYXNzd29yZA==
  3. Send in header: Authorization: Basic dXNlcjpwYXNzd29yZA==
✅ Use For Internal APIs, dev environments, CLI tools
❌ Avoid For 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

HTTPS ALWAYS use TLS — Base64 is trivially decoded
Secrets Never hardcode credentials in source code
Scope Limit to internal or trusted networks only

✅ When Basic Auth Is OK

Server-to-server with TLS mutual auth
Development/testing environments
One-off scripts with rotated credentials

Comparison & Recommendations

API Keys

Best For

Server-to-server APIs, rate limiting, usage tracking, simple integrations.

Pros Simple, easy to implement, good for tracking
Cons No user context, hard to rotate at scale
OAuth 2.0

Best For

Third-party integrations, social login, delegated authorization, enterprise apps.

Pros Industry standard, granular scopes, no password sharing
Cons Complex implementation, multiple flows to support
JWT

Best For

Stateless APIs, microservices, distributed systems, mobile apps.

Pros No DB lookup, contains user claims, scalable
Cons Can't revoke easily, larger than session IDs