
Rest API Authentication
1. Basic Authentication
Basic Authentication sends a username and password with every HTTP request, encoded in Base64. It is the simplest authentication method but also the least secure without HTTPS.
How Basic Auth Works
The client combines username and password into a single string (username:password), Base64-encodes it, and sends it in the Authorization header. The server decodes and validates the credentials against its user store.
GET /api/data HTTP/1.1
Host: api.example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=Python implementation:
import requests
from requests.auth import HTTPBasicAuth
response = requests.get(
"https://api.example.com/data",
auth=HTTPBasicAuth("username", "password")
)
print(response.status_code)When to Use Basic Auth
Internal APIs behind a VPN or firewall
Development and testing environments
Simple server-to-server calls where token management is overkill
Limitations
Credentials sent with every request (larger attack surface)
Base64 is encoding, not encryption. Without HTTPS, credentials are visible in plaintext.
No built-in session management or token expiration
2. API Key Authentication
API Keys are static, long alphanumeric strings assigned to an application or developer. They identify the caller and are commonly used for rate limiting, usage tracking, and basic access control.
How API Keys Work
The API provider generates a unique key. The client includes it in every request, either as a query parameter or in a custom header. The server validates the key against its database of authorized keys.
# As a header (preferred)
GET /api/data HTTP/1.1
X-API-Key: sk_live_abc123def456
# As a query parameter (less secure)
GET /api/data?api_key=sk_live_abc123def456When to Use API Keys
Public APIs with rate limiting (Google Maps, OpenWeather)
Server-to-server communication where user identity is not needed
Internal microservice authentication combined with an API gateway
Limitations
API keys identify the application, not the user. They cannot distinguish between different end users.
Static by nature. If leaked, they remain valid until manually revoked.
No built-in expiration or scope control
3. JWT (JSON Web Token) Authentication
JWT authentication uses digitally signed, self-contained tokens that carry user information. Unlike API keys, JWTs are stateless: the server does not need to store session data because all the information it needs is embedded in the token itself.
How JWT Works
A JWT has three Base64-encoded parts separated by dots: Header (algorithm and token type), Payload (claims like user ID, roles, expiration), and Signature (cryptographic verification). The server signs the token with a secret key or RSA private key. Any tampering invalidates the signature.
# JWT structure
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxMDAwMH0.signature
# Header: {"alg": "HS256"}
# Payload: {"user_id": 123, "role": "admin", "exp": 1710000}
# Signature: HMAC-SHA256(header + payload, secret)Python implementation:
import requests
# Step 1: Authenticate and get JWT
auth_response = requests.post(
"https://api.example.com/auth/login",
json={"email": "[email protected]", "password": "secure123"}
)
token = auth_response.json()["access_token"]
# Step 2: Use JWT in subsequent requests
headers = {"Authorization": f"Bearer {token}"}
data = requests.get("https://api.example.com/dashboard", headers=headers)
print(data.json())When to Use JWT
Single-page applications (SPAs) and mobile apps
Microservice architectures where services need to verify identity without a central session store
APIs where you need to embed user roles, permissions, or tenant IDs in the token
JWT vs. Opaque Tokens
JWT: Self-contained, verifiable without a database call. Larger payload. Cannot be revoked without a blocklist.
Opaque tokens: Random strings that require a server-side lookup. Smaller payload. Instantly revocable.
Limitations
Tokens cannot be revoked once issued (without maintaining a server-side blocklist)
Payload is readable by anyone (Base64, not encrypted). Do not store sensitive data in JWT claims.
Token size can be large if too many claims are embedded
4. OAuth 2.0
OAuth 2.0 is the industry standard protocol for delegated authorization. It allows users to grant third-party applications limited access to their resources without sharing passwords. Google, GitHub, Microsoft, and most enterprise APIs use OAuth 2.0.
OAuth 2.0 Roles
Resource Owner: The user who owns the data
Client: The application requesting access
Authorization Server: Issues tokens after verifying the user (e.g., Google’s OAuth server)
Resource Server: Hosts the protected API
Grant Types
OAuth 2.0 defines several grant types for different scenarios:
Authorization Code + PKCE: The most secure flow. Used by web and mobile apps. The client receives an authorization code and exchanges it for tokens. PKCE (Proof Key for Code Exchange) prevents authorization code interception.
Client Credentials: Machine-to-machine authentication. No user involved. The client authenticates directly with its own credentials.
Device Code: For devices with limited input (smart TVs, CLI tools). The user authorizes on a separate device.
Important (OAuth 2.1 update): The upcoming OAuth 2.1 specification formally deprecates the Implicit Grant and Resource Owner Password Grant. If your API still uses these flows, plan to migrate to Authorization Code + PKCE.
OAuth 2.0 Flow (Authorization Code)
import requests
from requests_oauthlib import OAuth2Session
client_id = "your_client_id"
client_secret = "your_client_secret"
redirect_uri = "https://yourapp.com/callback"
# Step 1: Get authorization URL
oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=["read:user"])
auth_url, state = oauth.authorization_url("https://github.com/login/oauth/authorize")
print(f"Visit: {auth_url}")
# Step 2: User authorizes, you get callback with code
callback_url = input("Paste the callback URL: ")
# Step 3: Exchange code for token
token = oauth.fetch_token(
"https://github.com/login/oauth/access_token",
authorization_response=callback_url,
client_secret=client_secret
)
# Step 4: Access protected resources
response = oauth.get("https://api.github.com/user")
print(response.json())When to Use OAuth 2.0
Any API that needs third-party access (social logins, integrations)
APIs where users should control what data apps can access (scopes)
Enterprise APIs with complex permission models
Limitations
Complex to implement correctly. Misconfigured OAuth flows are a common source of security vulnerabilities.
Requires an authorization server (can use Auth0, Okta, or build your own)
Token management (refresh, revocation, storage) adds operational overhead
5. HMAC (Hash-Based Message Authentication)
HMAC authentication signs each API request using a shared secret key and a hash function (typically SHA-256). The server independently computes the same hash and compares it. If they match, the request is authentic and unaltered.
How HMAC Works
The client constructs a “string to sign” from request elements (HTTP method, path, timestamp, body), hashes it with the shared secret, and sends the signature in a header. The server repeats the computation. Any change to the request, even a single byte, produces a different hash.
import hmac
import hashlib
import time
import requests
secret_key = b"your_shared_secret"
timestamp = str(int(time.time()))
method = "GET"
path = "/api/v1/transactions"
# Create string to sign
string_to_sign = f"{method}\n{path}\n{timestamp}"
signature = hmac.new(secret_key, string_to_sign.encode(), hashlib.sha256).hexdigest()
# Send request with signature
headers = {
"X-Timestamp": timestamp,
"X-Signature": signature,
"X-API-Key": "your_api_key"
}
response = requests.get(f"https://api.example.com{path}", headers=headers)
print(response.json())When to Use HMAC
Webhook verification: Stripe, GitHub, and Shopify all sign webhook payloads with HMAC so you can verify they are genuine
Payment and financial APIs: Request integrity is critical. HMAC proves the request was not tampered with in transit.
AWS API requests: AWS Signature Version 4 is an HMAC-based signing process used for all AWS API calls
Limitations
Requires precise clock synchronization between client and server (timestamps prevent replay attacks)
Both parties must securely store the shared secret
More complex to implement than API keys or Bearer tokens
6. OpenID Connect (OIDC)
OpenID Connect is an identity layer built on top of OAuth 2.0. While OAuth 2.0 handles authorization (“what can this app access?”), OIDC adds authentication (“who is this user?”). It returns an ID Token (a JWT containing user profile claims) alongside the OAuth access token.
How OIDC Differs from OAuth 2.0
OAuth 2.0 alone: You get an access token. You know the app is authorized, but you do not know who the user is without making an additional API call.
OAuth 2.0 + OIDC: You get an access token AND an ID token. The ID token contains the user’s identity (name, email, profile picture) directly.
When to Use OIDC
Single Sign-On (SSO): “Sign in with Google/Microsoft/Okta” flows all use OIDC
Enterprise APIs where knowing the user’s identity (not just that they are authorized) is required for audit trails or personalization
APIs that need standardized user profile data across multiple identity providers
Limitations
Adds complexity on top of OAuth 2.0. If you only need application-level access, plain OAuth is simpler.
ID Token validation requires verifying the JWT signature, audience, issuer, and expiration
7. mTLS (Mutual TLS)
Mutual TLS extends standard TLS by requiring both the client and server to present X.509 certificates during the handshake. In regular HTTPS, only the server proves its identity. With mTLS, both sides authenticate each other at the transport layer before any application data is exchanged.
How mTLS Works
The client presents a certificate signed by a trusted Certificate Authority (CA). The server validates it against its trust store. If valid, the TLS connection is established. No tokens, passwords, or API keys are needed at the application layer.
import requests
response = requests.get(
"https://api.bank.com/accounts",
cert=("/path/to/client.crt", "/path/to/client.key"),
verify="/path/to/ca-bundle.crt"
)
print(response.json())When to Use mTLS
Zero-trust architectures: Service mesh communication (Istio, Linkerd) uses mTLS between all microservices
Financial-grade APIs: Open Banking standards (PSD2 in the EU, FDX in the US) require mTLS for API access
Government and healthcare APIs: Where regulatory requirements demand certificate-based authentication
Limitations
Certificate management is operationally complex (issuance, rotation, revocation, CA infrastructure)
Not suitable for browser-based or mobile applications where installing client certificates is impractical
Debugging TLS handshake failures is harder than debugging token-based auth issues
How to Choose the Right Authentication Method
Use this decision framework based on three questions:
1. Who needs access?
End users (humans): OAuth 2.0 + OIDC for third-party apps, JWT for first-party apps
Applications/services: API Keys for simple cases, Client Credentials (OAuth) for enterprise, mTLS for zero-trust
Webhooks/callbacks: HMAC signatures
2. How sensitive is the data?
Public/low sensitivity: API Keys are sufficient
User data/PII: OAuth 2.0 with scopes, JWT with short expiration
Financial/healthcare/regulated: mTLS + OAuth 2.0, HMAC for request integrity
3. Do you need third-party delegation?
Yes: OAuth 2.0 is the only standard answer
No: JWT or API Keys depending on whether you need user identity
Once your API is authenticated, you can build embedded analytics on REST API data for your customers.
Comparison Table: REST API Authentication Methods
| Method | Security Level | Best For | Identifies User? | Stateless? | Implementation Complexity |
|---|---|---|---|---|---|
| Basic Auth | Low (requires HTTPS) | Internal APIs, testing | Yes | Yes | Very low |
| API Keys | Low-Medium | Server-to-server, rate limiting | No (identifies app) | Yes | Low |
| JWT | Medium-High | SPAs, mobile apps, microservices | Yes (via claims) | Yes | Medium |
| OAuth 2.0 | High | Third-party access, enterprise APIs | No (add OIDC for identity) | Token-based | High |
| HMAC | High | Webhooks, payment APIs, AWS | No (verifies integrity) | Yes | Medium-High |
| OpenID Connect | High | SSO, user identity verification | Yes (ID Token) | Token-based | High |
| mTLS | Very High | Zero-trust, financial APIs, regulated industries | Yes (via certificate) | Yes | Very High |
REST API Security Best Practices
Regardless of which authentication method you choose, follow these practices:
Always use HTTPS/TLS. Every method on this list is vulnerable without encrypted transport.
Set short token lifetimes. JWTs should expire in 15-60 minutes. Use refresh tokens for longer sessions.
Rotate secrets and keys regularly. Automate rotation where possible (AWS Secrets Manager, HashiCorp Vault).
Implement rate limiting. Protect against brute force and credential stuffing attacks.
Never store secrets in client-side code. API keys in JavaScript bundles or mobile app binaries are extractable.
Use an API gateway. Centralize authentication, rate limiting, and logging in one layer (Kong, AWS API Gateway, Apigee).
Log and monitor authentication events. Track failed attempts, unusual patterns, and token usage for security auditing.
Validate all inputs. Authentication does not replace input validation. SQL injection, XSS, and other attacks can bypass authenticated endpoints.
Join Techsnap Creators
Share your knowledge and earn ??
Want to showcase your tech expertise and get rewarded for your insights? Join the Techsnap creator network!
Write insightful blogs, stay ahead of industry trends, and grow your professional brand while helping others in the community.
Ready to make an impact?

Comments