← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

API Authentication Patterns

API Design Intermediate
debt(d5/e7/b7/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The term's detection_hints list semgrep and owasp-zap as tools that can catch common misuses like API keys in query parameters, unsigned JWTs (alg:none), and missing token expiry. These are specialist SAST/DAST tools, not default linters. Some issues like insufficient token scoping or missing revocation strategies require careful code review, pushing toward d7, but the automated detection of the most common code patterns (confirmed automated: yes) keeps this at d5.

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix is a conceptual guideline ('use the simplest pattern that meets your requirements'), not a one-line replacement. Switching from one auth pattern to another (e.g., from long-lived API keys to JWT + refresh tokens, or adding OAuth2 for delegated access) requires changes across authentication middleware, token issuance, token validation, client code, and often database schema for refresh token/blocklist storage. This is inherently cross-cutting. Not quite e9 because it doesn't necessarily require a full architectural rewrite — it's a significant but bounded refactor.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). Authentication pattern choice applies to web and API contexts and shapes every endpoint's security model, middleware stack, session management, and client integration. Per the tags (api-design, security, auth), this is a load-bearing architectural decision. Every new endpoint, every new service-to-service call, and every client must conform to the chosen auth pattern. It doesn't quite define the entire system's shape (b9) since other architectural dimensions exist independently, but it strongly shapes every change involving access control.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field is explicit: developers believe 'JWT authentication is stateless and therefore cannot be revoked,' which is a half-truth that leads to dangerous design decisions (no blocklist, long-lived tokens). Additional common_mistakes like accepting alg:none tokens and putting API keys in query parameters are traps where the 'obvious' approach (just pass the key as a parameter, trust the JWT header) is wrong. The JWT statelessness misconception is particularly insidious because 'stateless' is marketed as a feature, leading developers to skip revocation mechanisms entirely.

About DEBT scoring →

Also Known As

Bearer token API key authentication mTLS HMAC signing JWT authentication

TL;DR

Bearer tokens (JWT) for user sessions, API keys for machine-to-machine, mTLS for highest-security internal services — matching authentication method to the use case.

Explanation

API authentication options: Bearer token (Authorization: Bearer jwt) — stateless JWT, validate signature/expiry/issuer; use short expiry (15min) + refresh tokens. API key (X-API-Key header) — hash stored server-side, scope keys to minimum required permissions, rate-limit per key. Basic auth — only with HTTPS, legacy use only. OAuth 2.0 client credentials — for third-party apps accessing your API on their own behalf. mTLS (mutual TLS) — both client and server present certificates, no passwords, ideal for internal microservices. HMAC request signing (AWS Signature v4 style) — signs request body and headers, prevents replay attacks.

Common Misconception

JWT authentication is stateless and therefore cannot be revoked — JWTs cannot be revoked without maintaining a blocklist (which adds state); for revocability, use short-lived tokens (15min) where the window of exposure is acceptable, or use opaque tokens with server-side session lookup.

Why It Matters

API key authentication for public user-facing APIs means one leaked key compromises that entire user's access — JWT with short expiry + refresh tokens limits blast radius and enables revocation via refresh token blocklist.

Common Mistakes

  • Long-lived JWT tokens without revocation — a leaked token remains valid until expiry
  • API keys in URL query parameters — logged by servers, CDNs, browser history, and proxies
  • No token scoping — one token with full access means any leak is a full compromise
  • JWT without signature validation — accepting unsigned tokens with alg:none

Avoid When

  • Using API keys in URLs — they appear in server logs, browser history, and referrer headers.
  • Long-lived tokens with no expiry or rotation — a stolen token is valid forever.
  • Storing API keys in client-side JavaScript — they are visible to anyone who views source.
  • Using HTTP Basic Auth over plain HTTP — credentials are sent in every request, base64-encoded but not encrypted.

When To Use

  • API keys for server-to-server calls where the key can be stored securely in environment variables.
  • OAuth 2.0 + PKCE for user-delegated access — never embed client secrets in mobile or SPA clients.
  • JWT bearer tokens for stateless APIs where the token carries claims without server-side session lookup.
  • mTLS for high-trust service-to-service communication in zero-trust network environments.

Code Examples

✗ Vulnerable
// Long-lived JWT — leaked token valid for 1 year:
$token = JWT::encode([
    'sub' => $userId,
    'exp' => time() + 31536000, // 1 year expiry!
], $secretKey);
// Leaked token: full access for up to 1 year

// API key in URL — logged everywhere:
GET /api/data?api_key=sk_live_abc123
✓ Fixed
// Short-lived access token + refresh token:
$access  = JWT::encode(['sub'=>$userId,'exp'=>time()+900], $key);  // 15 min
$refresh = JWT::encode(['sub'=>$userId,'exp'=>time()+2592000], $refreshKey); // 30 days
// Leaked access token: valid at most 15 min
// Refresh tokens: stored and rotatable

// API key in header — not logged by default:
// Authorization: Bearer $access
// OR: X-API-Key: sk_live_abc123

Added 16 Mar 2026
Edited 25 Mar 2026
Views 88
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 3 pings F 2 pings S 2 pings S 1 ping M 0 pings T 3 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 1 ping T 1 ping W 2 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 17 Google 12 Perplexity 10 Scrapy 10 SEMrush 5 Ahrefs 4 Bing 3 Unknown AI 2 Claude 2 ChatGPT 1 Meta AI 1 PetalBot 1
crawler 65 crawler_json 3
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
API keys for server-to-server, JWT for stateless user sessions, OAuth2 for third-party delegated access — use the simplest pattern that meets your actual requirements
📦 Applies To
any web api laravel symfony
🔗 Prerequisites
🔍 Detection Hints
API key in URL query parameter instead of Authorization header; long-lived JWT tokens with no refresh mechanism; no token expiry
Auto-detectable: ✓ Yes semgrep owasp-zap
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: High Context: File Tests: Update
CWE-287 CWE-306


✓ schema.org compliant