There are five ways to authenticate an API request — and each one is the right choice in different contexts
The first time you use a new API, you copy a key from a dashboard into an Authorization header and it works. The problem is that the same approach — API key in a header — is appropriate for some situations and wrong for others. OAuth 2.0 exists because API keys don't fit every authentication pattern. HMAC signatures exist because API keys can be stolen in transit even over HTTPS. Understanding when each method makes sense prevents both over-engineering and under-securing.
1. API Keys
What it is: a static secret token, typically a random string, included in requests. Usually in an HTTP header or query parameter.
GET /api/data HTTP/1.1
Host: api.example.com
X-API-Key: sk_live_abc123xyz
Or as a query parameter (less secure — appears in logs):
https://api.example.com/data?api_key=sk_live_abc123xyz
How it works: the server looks up the API key in its database. If found and not revoked, the request is authorised with the permissions associated with that key.
When it's right:
- Server-to-server communication
- Developer access to third-party APIs
- Internal service authentication within a trusted network
- Any context where the key is stored server-side and never exposed to end users
When it's wrong:
- Client-side code (the key is visible to anyone who inspects the source)
- Mobile apps (keys embedded in app binaries can be extracted)
- Any scenario requiring user-level access control or delegation
Security considerations: rotate keys regularly, use different keys per environment (dev/staging/prod), use short-lived keys where possible, never put keys in URLs (they appear in server logs and browser history).
2. Bearer Tokens (JWT)
What it is: a token included in the Authorization header with the Bearer scheme.
GET /api/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.signature
How it works: the server decodes the token (typically a JWT) and verifies the signature. Claims in the token payload specify the user identity, permissions, and expiry.
When it's right:
- User-authenticated API calls
- Short-lived access tokens in OAuth 2.0 flows
- Microservices authentication where tokens are passed between services
- Mobile apps where tokens can be securely stored
When it's wrong:
- Long-lived tokens without expiry (creates a revocation problem)
- Tokens stored in
localStorageon web clients (XSS vulnerability) - Sensitive data in the token payload without encryption
3. Basic Authentication
What it is: username and password encoded in Base64 and included in the Authorization header.
GET /api/data HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Where dXNlcm5hbWU6cGFzc3dvcmQ= is base64("username:password").
Important: Base64 is encoding, not encryption. The credentials are trivially decoded. Basic Auth provides no security without HTTPS.
When it's right:
- Internal tools and admin interfaces where simplicity is valued
- Legacy APIs that don't support modern auth
- Testing and development environments
- APIs where the client is trusted (internal services using service accounts)
When it's wrong:
- Any public-facing API
- Without HTTPS (credentials transmitted in plain text)
- When users expect password-based sessions (use session cookies instead)
4. OAuth 2.0
What it is: a framework for delegated authorisation. A user (the resource owner) grants a client application access to their resources on another service, without sharing their password.
User → approves → Client App → gets access token from → Auth Server
Client App → uses access token to → Resource Server
The flows:
- Authorization Code (web apps): user redirects to auth server, approves, receives a code, client exchanges code for tokens
- Client Credentials (server-to-server): no user involved; client authenticates directly with client ID and secret
- PKCE (Proof Key for Code Exchange): for mobile/SPA apps where a client secret can't be securely stored
When it's right:
- "Login with Google/GitHub/Apple" flows
- Third-party integrations where users grant an app access to their data
- Any context involving delegated access to user resources
- Separating authentication (who are you?) from authorisation (what can you do?)
When it's wrong:
- Simple first-party API authentication where the complexity isn't justified
- Server-to-server calls where Client Credentials would suffice
5. HMAC Signatures
What it is: a cryptographic signature of the entire request, generated by hashing the request content with a shared secret.
import hmac, hashlib, time, json
def sign_request(payload, secret_key):
timestamp = str(int(time.time()))
message = f"{timestamp}.{json.dumps(payload, separators=(',', ':'))}"
signature = hmac.new(
secret_key.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return signature, timestamp
# Include in request:
# X-Timestamp: {timestamp}
# X-Signature: {signature}
How it works: the server recomputes the signature using the same algorithm and shared secret. If the computed signature matches the provided signature, the request is authenticated. The signature covers the request body, so tampering is detected.
When it's right:
- Webhook verification (Stripe, GitHub, Twilio all use HMAC to verify webhook deliveries)
- High-security server-to-server communication
- Any context where request integrity (not just authentication) must be verified
- Preventing replay attacks (include timestamp in the signature)
When it's wrong:
- User-facing authentication (users don't have shared secrets)
- Complex to implement correctly — usually overkill when TLS-protected API keys suffice
Testing each authentication type with the REST API Checker
API Key:
Header: X-API-Key: your-key-here
Bearer Token:
Header: Authorization: Bearer your-token-here
Basic Auth:
Header: Authorization: Basic base64(username:password)
Or use the tool's Basic Auth option if available.
OAuth Bearer (after completing OAuth flow):
Header: Authorization: Bearer access-token-from-oauth-flow
Webhook verification (HMAC): Compute the signature locally and include it:
Header: X-Hub-Signature-256: sha256=computed-hmac-here
Frequently Asked Questions
What's the difference between authentication and authorisation? Authentication: verifying identity ("who are you?"). Authorisation: verifying permissions ("what are you allowed to do?"). OAuth 2.0 specifically addresses authorisation (delegated access to resources). JWT typically carries both: the signature authenticates the token, the claims authorise specific actions.
Should I use API keys or OAuth 2.0 for a new public API? For developer-to-API access (server-side), API keys are simpler and sufficient. For user-facing access (mobile apps, web apps accessing user data), OAuth 2.0 with PKCE is appropriate. Many APIs support both: API keys for developer tools and direct integration, OAuth for user-level access.
Is the REST API Checker free? Yes — completely free, no sign-up required.
The authentication method should match the trust relationship: API keys for trusted server-to-server calls, Bearer tokens for user-authenticated requests, OAuth for delegated user access, HMAC for high-integrity webhooks. Using the wrong method doesn't always produce immediate failure — it produces inappropriate security properties that matter only when something goes wrong.
Try the REST API Checker free at sadiqbd.com — test any API endpoint with any authentication method, directly in your browser.