API Security, Auth & Rate Limiting
Published
The compressed essence. One page to glance at before an interview or a design review. Definitions live in Glossary.
AuthN vs AuthZ
Two questions, two failure codes — keep them distinct.
- Authentication — who you are
- Establishes identity. Missing or invalid credentials →
401 Unauthorized. → The client hasn’t proven who it is. - Authorization — what you may do
- Establishes permission once identity is known. Known principal, not permitted →
403 Forbidden. → We know who you are; you simply can’t do this.
Credential schemes
| Scheme | Use when | Watch out |
|---|---|---|
| API key | Server-to-server, simple identification of a calling app | Coarse-grained; hard to scope or rotate; never expose in a browser or in the URL |
| Bearer token | Caller presents a token it holds — sent in the Authorization header | Whoever holds it can use it; protect in transit, keep out of logs/URLs |
| OAuth 2.0 | Delegated authorization — let an app act on a user’s behalf without their password | It is a delegated-authorization framework, NOT authentication by itself |
| OIDC | You need to authenticate (identify) the end user — “sign in with…” | Adds an identity/authentication layer on top of OAuth 2; don’t conflate the two |
| mTLS | Service-to-service strong identity (both ends present certs) | Cert lifecycle / rotation overhead; usually internal, not public clients |
OAuth 2.0 grant types
Tokens carry scopes (coarse permissions) and an audience (aud) naming the intended resource.
| Grant | Use for | Note |
|---|---|---|
| Authorization Code + PKCE | Users on web / mobile / SPA | PKCE protects public clients (no client secret) against code interception |
| Client Credentials | Machine-to-machine, no user present | App authenticates as itself with its own secret |
| Implicit | — | LEGACY · do not use (superseded by Code + PKCE) |
| Resource-Owner Password | — | LEGACY · do not use (app handles the user’s password) |
JWT vs server-side sessions
| JWT (token) | Server-side session | |
|---|---|---|
| Shape | Self-contained, signed: header.payload.signature | Opaque session id; data lives server-side |
| Validation | Stateless — any node verifies the signature locally (fits REST statelessness) | Stateful — shared store or sticky sessions required |
| Confidentiality | base64 is encoded, not encrypted — put no secrets inside | Payload never leaves the server |
| Revocation | Hard before expiry → short-lived access tokens + rotating refresh tokens + denylist / introspection | Easy — delete the session |
JWT validation checklist: verify the signature; pin the algorithm (reject alg: none and alg-confusion); check iss, aud, and exp/nbf. The stateless win is real, but you trade away easy revocation — pure statelessness vs. instant logout is the design tension.
Authorization models
- RBAC — role-based
- Permissions attach to roles; principals get roles. Simple, coarse. → “editors can publish.”
- ABAC — attribute-based
- Decisions from attributes of subject / resource / environment. Fine-grained, dynamic. → “owner can edit during business hours.”
- Object-level authZ (the one that bites)
- Verify the principal owns or may act on this specific object — not merely that they’re authenticated. → Missing this check is OWASP API1 / BOLA, the #1 API risk.
OWASP API Security Top 10 (2023)
Condensed. OWASP API Security Top 10.
| ID | Risk |
|---|---|
| API1 | BOLA — Broken Object Level Authorization · #1 / most common |
| API2 | Broken Authentication |
| API3 | BOPLA — Broken Object Property Level Authorization |
| API4 | Unrestricted Resource Consumption |
| API5 | BFLA — Broken Function Level Authorization |
| API6 | Unrestricted Access to Sensitive Business Flows |
| API7 | Server-Side Request Forgery (SSRF) |
| API8 | Security Misconfiguration |
| API9 | Improper Inventory Management |
| API10 | Unsafe Consumption of APIs |
Rate limiting
On throttle return 429 Too Many Requests + Retry-After; expose RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset. Limit per principal / key / account (per IP for anonymous). Protects availability (OWASP API4).
| Algorithm | Behaviour |
|---|---|
| Fixed window | Count per clock window. Simple, but allows boundary bursts at window edges. |
| Sliding window | Rolling interval — smoother than fixed; no edge double-spend. |
| Token bucket | Bursts up to a cap, then steady refill. Common — allows spikes within limits. |
| Leaky bucket | Drains at a constant rate — smooths the output regardless of input bursts. |
Hygiene checklist
- Transport & storage
- TLS everywhere; never put tokens in URLs / query strings (they land in logs and history).
- Browser cookies
- Set
HttpOnly+Secure+SameSite. - Secrets & scope
- Rotate secrets regularly; grant least-privilege scopes.
- Errors
- Consistent RFC 9457 Problem Details that leak no internals (no stack traces, no internal IDs).