Table of Contents

Why API Security Is Non-Negotiable

APIs are the backbone of modern software. Your mobile app talks to an API. Your SaaS dashboard reads from an API. Your payment processor, your authentication layer, your third-party integrations — all APIs. That makes them the single most targeted attack surface in 2026.

The Verizon Data Breach Report consistently finds that web application attacks — most of which target APIs — account for the majority of confirmed data breaches. A single misconfigured endpoint can expose millions of user records, allow account takeover, or leak business-critical data.

The good news: most API attacks exploit well-known, preventable mistakes. This guide covers the practices that close those gaps.


1. Authenticate Every Request

Never trust an unauthenticated request. Every API endpoint should require proof of identity unless you have a deliberate, documented reason to make it public.

Use industry-standard authentication

  • OAuth 2.0 + OpenID Connect — the gold standard for delegated authorization. Use it when users need to grant third-party apps access to their data.
  • JWT (JSON Web Tokens) — compact, stateless tokens for API-to-API or client-to-server authentication. Keep them short-lived (15 minutes to 1 hour).
  • API Keys — acceptable for server-to-server communication. Never expose them client-side.

JWT security checklist

✓ Sign with RS256 (asymmetric) not HS256 where possible
✓ Validate the "alg" header — reject "none"
✓ Set a short expiry (exp claim)
✓ Validate issuer (iss) and audience (aud)
✓ Store on the server side in httpOnly cookies, not localStorage
✓ Implement refresh token rotation

Common authentication mistakes

  • Accepting expired tokens because expiry validation was skipped
  • Using symmetric secrets that are too short or reused across environments
  • Sending API keys in URL query strings (they end up in server logs)
  • Not revoking tokens on logout

2. Use HTTPS Everywhere — No Exceptions

All API traffic must travel over TLS 1.2 or TLS 1.3. HTTP is unacceptable — credentials, tokens, and sensitive data transmitted over plain HTTP can be intercepted trivially with a packet sniffer.

Enforce it:

  • Configure your server to reject non-HTTPS connections entirely — redirect or drop them
  • Set Strict-Transport-Security (HSTS) headers so browsers remember to use HTTPS
  • Use TLS 1.3 where possible — it is faster and more secure than 1.2
  • Pin certificates in mobile clients if your threat model warrants it

Check your TLS configuration with SSL Labs (ssllabs.com/ssltest) before going to production. Aim for an A or A+ rating.


3. Implement Rate Limiting and Throttling

Without rate limiting, your API is open to:

  • Brute force attacks — automated credential stuffing against login endpoints
  • Denial of service — a single abusive client consuming all your resources
  • Enumeration attacks — bots cycling through IDs or emails to harvest data
  • Scraping — competitors harvesting your content at machine speed

How to implement it

Rate limit by IP address AND by authenticated user ID. IP-only limits are trivially bypassed with IP rotation.

# Example: FastAPI with slowapi
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)

@app.get("/api/login")
@limiter.limit("5/minute")   # 5 login attempts per minute per IP
async def login(request: Request, ...):
    ...

Recommended limits by endpoint type:

Endpoint TypeSuggested Limit
Login / auth5–10 / minute
Password reset3 / hour
General read100–300 / minute
Write / POST30–60 / minute
Search20–50 / minute

Return 429 Too Many Requests with a Retry-After header so clients know when to back off. Never silently drop requests — log them.


4. Validate and Sanitize All Input

Every piece of data that enters your API from the outside world is untrusted. Treat it that way.

What to validate

  • Type — is this actually a number, not a string containing '; DROP TABLE users;--?
  • Range — is age: 9999 a valid age?
  • Length — is a 50,000-character “username” ever legitimate?
  • Format — does this match the expected pattern (email, UUID, date)?
  • Allowed values — if the field should be one of ["admin", "user", "guest"], reject anything else

Use a schema validation library

Never write manual validation logic for complex objects. Use battle-tested libraries:

  • Python: Pydantic, marshmallow
  • Node.js: Zod, Joi, Yup
  • Go: go-playground/validator
  • Java: Hibernate Validator (Bean Validation)
# Pydantic example — invalid data is rejected before it touches your logic
from pydantic import BaseModel, EmailStr, Field

class CreateUserRequest(BaseModel):
    email: EmailStr
    username: str = Field(min_length=3, max_length=32, pattern=r'^[a-zA-Z0-9_]+$')
    age: int = Field(ge=13, le=120)

SQL injection is still killing APIs

Parameterised queries and ORMs protect you from SQL injection. Raw string concatenation does not:

# WRONG — never do this
query = f"SELECT * FROM users WHERE email = '{user_input}'"

# RIGHT — parameterised
cursor.execute("SELECT * FROM users WHERE email = %s", (user_input,))

5. Return the Minimum Data Necessary

Mass assignment and over-fetching are two of the most common API vulnerabilities.

Mass assignment happens when your API blindly binds request data to a model:

# WRONG — attacker can set is_admin=true in the request body
user = User(**request.json())

# RIGHT — explicitly select which fields are writable
user = User(
    name=data["name"],
    email=data["email"]
)

Over-fetching happens when your API returns entire objects when only a few fields are needed. If your /users/me endpoint returns password_hash, stripe_customer_id, and internal_notes alongside the user’s name — that is a data exposure risk.

Explicitly define your response schemas and serialise only what the client needs.


6. Version Your API

Versioning keeps you from breaking clients while giving you the freedom to make security improvements. If you discover a vulnerability in your current API design, you can fix it in v2 without forcing immediate changes on all consumers.

Use URL versioning (/api/v1/, /api/v2/) — it is explicit and easy to route:

GET /api/v1/users/123   ← old clients still work
GET /api/v2/users/123   ← new, more secure design

Set a clear deprecation timeline and communicate it to API consumers. Do not leave insecure old versions running indefinitely.


7. Log Everything — Then Monitor It

Logs are useless if no one reads them. Set up structured logging and active monitoring from day one.

Log every request (at minimum):

  • Timestamp
  • Request method and path
  • Response status code
  • Authenticated user ID (if any)
  • IP address
  • Response time

Alert on:

  • Sudden spike in 401 or 403 responses (credential stuffing or enumeration)
  • Spike in 500 errors (something broke — possibly under attack)
  • Requests from a single IP hitting many different endpoints quickly (scanning)
  • Requests for endpoints that do not exist (reconnaissance)

Tools worth knowing: Datadog, Grafana + Loki, ELK Stack, Sentry, AWS CloudWatch.


8. Know the OWASP API Top 10

The OWASP API Security Top 10 is the definitive list of the most critical API risks. Every API developer should know it:

#RiskWhat It Means
1Broken Object Level Authorization (BOLA)Users accessing other users’ objects via ID manipulation
2Broken AuthenticationWeak tokens, missing expiry, no brute-force protection
3Broken Object Property Level AuthorizationReturning or accepting fields a user should not touch
4Unrestricted Resource ConsumptionNo rate limits — API is exhausted by a single client
5Broken Function Level AuthorizationRegular users accessing admin endpoints
6Unrestricted Access to Sensitive Business FlowsBots exploiting checkout, registration, or voting flows
7Server Side Request Forgery (SSRF)API fetches URLs from user input — attacker points it inward
8Security MisconfigurationDefault credentials, verbose errors, open CORS
9Improper Inventory ManagementForgotten debug/staging endpoints exposed in production
10Unsafe Consumption of APIsTrusting third-party API responses without validation

BOLA (number one) is the most commonly exploited. The fix: always check that the authenticated user owns the resource they are requesting — never trust the ID in the request alone.


Quick Security Checklist

Before you ship any API to production, run through this list:

Authentication
  ✓ Every endpoint requires auth (or is explicitly documented as public)
  ✓ Tokens are short-lived and rotated
  ✓ Secrets are in environment variables, not source code

Transport
  ✓ HTTPS enforced — HTTP rejected
  ✓ TLS 1.2+ only, TLS 1.3 preferred
  ✓ HSTS header set

Input / Output
  ✓ All input validated with a schema library
  ✓ Parameterised queries used everywhere
  ✓ Responses expose only necessary fields

Access Control
  ✓ Object-level ownership checked on every read/write
  ✓ Admin and privileged endpoints require explicit role check
  ✓ CORS configured to specific origins only

Operational
  ✓ Rate limiting on all public endpoints
  ✓ Structured logging in place
  ✓ Error messages do not expose stack traces to clients
  ✓ API versioned

Security is not a feature you bolt on at the end — it is a design discipline you apply from the first line of code. Start with these practices and you will avoid the vulnerabilities that compromise most APIs in the wild.