---
name: api-security-best-practices
description: "API security against the OWASP API Top 10: object-level authorization, token handling, input validation, rate limits, secrets. Use when building, reviewing or hardening an HTTP API or its auth layer."
metadata:
  risk: safe
  source: multi-agent-pipeline
  date_added: "2026-09-25"
---

# API Security Best Practices

Most API breaches are not clever. A caller changes an id in the URL and reads
someone else's order; a client sends `"role": "admin"` in a profile update and
the server saves it; an endpoint returns the whole database row and the app
hides the sensitive columns in the UI. The controls below close those holes.
They are organised around the OWASP API Security Top 10 (2023) because that
list reflects how APIs are actually attacked.

This skill is for building and reviewing controls. For a structured audit of a
whole diff or repository with CVSS-scored findings, use `security-review`.

## Reference files

| File | Load it when |
|---|---|
| `references/identity-and-access.md` | Validating tokens, sessions, API keys, service identity, writing authorization checks |
| `references/request-handling.md` | Validating input, shaping responses, preventing injection, SSRF and mass assignment |
| `references/abuse-controls.md` | Rate limits, quotas, payload limits, bot and enumeration defence |
| `references/operations.md` | Secrets, TLS and headers, security logging, testing the controls |

## The ten risks as questions

Ask each question of every endpoint you add or review. A "no" or "not sure" is
a finding.

### API1 Broken object level authorization (BOLA)

*Does the handler prove this caller may touch this specific object?*

Authentication says who the caller is; it says nothing about whether order
`o_4411` belongs to them. Scope every lookup by the principal, in the query
itself, not in a check after the fetch.

Query: `references/identity-and-access.md`.

Return 404, not 403, for rows the caller cannot see, so ids cannot be
probed. Opaque random ids (UUIDv7, ULID) help but are not a control on their own.

### API2 Broken authentication

*Is every credential verified the same strict way on every route?*

- Verify JWT signature, `alg` against an allowlist, `iss`, `aud`, `exp` and
  `nbf`. Never accept `alg: none` or let the token choose the key.
- Short-lived access tokens (5 to 15 minutes); rotate refresh tokens and detect
  reuse.
- Rate limit and lock out credential endpoints (login, OTP, password reset).
- Prefer a maintained identity provider or library over hand-rolled crypto.

### API3 Broken object property level authorization

*Can the caller read or write a field they should not?*

This merges the old "excessive data exposure" and "mass assignment" risks.

- Response: serialise through an explicit output schema per audience; never
  return the ORM entity.
- Request: bind to an input schema that lists writable fields; reject or drop
  everything else. `isAdmin`, `accountId`, `priceOverride` are never
  client-writable.

### API4 Unrestricted resource consumption

*What stops one caller from exhausting CPU, memory, storage, money or a
downstream quota?*

Rate limits per identity, body size caps, page size caps, timeouts, GraphQL
depth and cost limits, upload size and type limits, and spend caps on anything
that calls a paid provider (SMS, email, LLM). See `references/abuse-controls.md`.

### API5 Broken function level authorization

*Is every privileged operation gated by role or permission on the server?*

Admin routes hidden from the UI are still reachable. Enforce permissions in
middleware or a policy layer that denies by default, and test that an ordinary
user gets 403 on each admin route.

### API6 Unrestricted access to sensitive business flows

*Could a script abuse this flow even though each request is individually valid?*

Checkout of limited stock, coupon redemption, account sign-up, review posting.
Controls are business-aware: per-account and per-device limits, velocity checks,
proof-of-work or CAPTCHA at the right step, and human review queues.

### API7 Server side request forgery (SSRF)

*Does any endpoint fetch a URL the caller supplied?* Fetch only through an
allowlisting, private-range-rejecting client; details in
`references/operations.md`.

### API8 Security misconfiguration

*Is the deployment as strict as the code?*

TLS everywhere, HSTS, CORS limited to known origins (never reflect the `Origin`
header with credentials), verbose errors off in production, default accounts
removed, security headers set, unused HTTP methods rejected.

### API9 Improper inventory management

*Do you know every API version and host that is live?*

Old `/v1` routes, staging hosts with production data, forgotten debug
endpoints. Keep an inventory generated from code (OpenAPI), retire versions on a
schedule, and apply the same gateway policies to every environment that holds
real data.

### API10 Unsafe consumption of APIs

*Do you trust third-party responses more than user input?*

Validate upstream payloads against a schema, set timeouts and size limits,
follow redirects only deliberately, and never pass upstream strings into SQL,
shell or HTML unescaped.

## Operating the controls

Detail: `references/operations.md`. Secrets come from a
secret store with per-environment keys, rotation and hashed API keys, never
in logs; TLS 1.2+ with HSTS, `no-store` on sensitive responses and `nosniff`;
structured security events with alerts on 401/403/404 bursts; and BOLA,
privileged-route, mass-assignment and size-limit tests in the suite, plus
dependency audit and a DAST baseline in CI.

## Review checklist

- [ ] Every object lookup is scoped by the caller's identity or tenant.
- [ ] Token validation checks signature, algorithm allowlist, issuer, audience, expiry.
- [ ] Input and output go through explicit schemas; no raw entities returned.
- [ ] Privileged routes deny by default and are covered by negative tests.
- [ ] Per-identity rate limits, body and page size caps, and timeouts are set.
- [ ] User-supplied URLs are fetched only through an SSRF-safe client.
- [ ] CORS, TLS, HSTS and error verbosity are production-strict.
- [ ] Secrets come from a secret store and never reach logs.
- [ ] Every live version and host is in the inventory.
- [ ] Third-party responses are validated like user input.

## Related skills

- `security-review`: full audit with threat model and scored findings.
- `api-patterns`: idempotency and error shapes that also limit abuse.
- `rest-api-design`: status code choices for auth failures.
- `nodejs-backend-patterns`, `fastapi-pro`: framework-level wiring.
- `ios-security`, `android-security`: client-side storage of the tokens issued here.

## External references

- OWASP API Security Top 10 2023: https://owasp.org/API-Security/editions/2023/en/0x11-t10/
- OWASP Cheat Sheet Series: https://cheatsheetseries.owasp.org/
- RFC 8725, JWT Best Current Practices: https://www.rfc-editor.org/rfc/rfc8725
