DEV Community

Cover image for API Security Best Practices Every Developer Should Know
Tien Nguyen
Tien Nguyen

Posted on Originally published at bezkoder.com

API Security Best Practices Every Developer Should Know

APIs are the backbone of modern software. They power mobile apps, connect microservices, expose data to partners, and drive entire business ecosystems. And yet, APIs are also one of the most commonly exploited attack surfaces in the wild.

Whether you're a startup shipping your first REST API or a platform team managing hundreds of internal services, the fundamentals of API security don't change. What does change is how thoroughly they're applied.

Here's a breakdown of 12 best practices that should be non-negotiable on any serious API project.

api-security-best-practices

1. Use Modern OAuth/OIDC + MFA

Passwords are a liability. If your API still accepts username/password credentials directly, that's a problem worth solving today.

The modern standard is OAuth 2.0 with PKCE (Proof Key for Code Exchange), combined with OpenID Connect (OIDC) for identity. PKCE prevents authorization code interception attacks - essential for public clients like mobile apps and SPAs.

On top of that, enforce Multi-Factor Authentication (MFA). Even if credentials are leaked, a second factor stops unauthorized access cold.

Issue short-lived JWT tokens (15-minute TTL is a solid default) and rely on your authorization server to handle the heavy lifting. Don't roll your own auth logic - the stakes are too high.

Key principle: Secure login with PKCE, short-lived tokens, and strong MFA.

2. Enforce Fine-Grained Authorization

Authentication asks who are you? Authorization asks what can you do? - and this is where most APIs fall short.

Broken Object Level Authorization (BOLA) is consistently ranked as the #1 API vulnerability. It happens when a user can access another user's data simply by changing an ID in the request. The classic example: user alex can access /orders/42, but can they also access /orders/99 owned by mallory? If your API doesn't check, attackers will.

Every request should pass three layers of checks before hitting the data layer:

  • Object Check - does this object belong to the requesting user?
  • Function Check - is this user allowed to call this HTTP method?
  • Field Check - should this user see these specific fields?

Authorization logic belongs at every layer, not just the route handler.

3. Minimize Scopes and Data

Least privilege isn't just a network security concept - it applies directly to API design.

When issuing tokens, scope them to exactly what the client needs. A mobile app that only reads user profiles doesn't need write access to billing records. When responding to requests, filter out fields the client has no business seeing. SSNs, internal IDs, salary figures, admin roles - if the client doesn't need it, strip it before it leaves the server.

Think of a scope filter as the last line of defense between your database and the outside world. The less you expose, the smaller your blast radius when something goes wrong.

4. Encrypt Every Hop

TLS is not optional. Neither is encrypting traffic between internal services.

A common misconception is that internal traffic - between your API gateway and your microservices - doesn't need encryption because it's "inside the network." That assumption fails the moment an attacker gains a foothold inside your infrastructure.

The right architecture looks like this:

  • External traffic: TLS 1.3 termination at the API Gateway
  • Internal traffic: mTLS (mutual TLS) between services, so both parties verify each other's identity

This model treats every network hop as untrusted. It's more operational overhead, but it significantly reduces the damage from a compromised internal service.

5. Protect Secrets and Keys

Hardcoded credentials in source code are a critical vulnerability. They end up in version control, get cloned by contractors, and eventually leak. The solution is centralized secret management.

Use an HSM-backed vault to store signing keys, client secrets, database credentials, and any other sensitive values. A good secrets management system provides:

  • Storage - secrets are never in plaintext on disk or in code
  • Rotation - credentials rotate automatically before they can be exploited
  • Revocation - compromised credentials can be invalidated instantly
  • Auditing - every access is logged with who, what, and when

HashiCorp Vault, AWS Secrets Manager, and GCP Secret Manager are mature options for most teams.

6. Validate Requests with Schemas

Never trust input. That's the rule. Everything coming into your API - headers, query parameters, request bodies - should be validated against a strict schema before any business logic runs.

A good schema validator will reject:

  • Wrong types - a string where a number is expected
  • Oversized payloads - a 50MB file upload to a text endpoint
  • Unknown fields - extra keys that shouldn't be there (they might be injection attempts)
  • Invalid values - internal IP addresses, malformed URLs, out-of-range numbers

Respond to malformed input with a 400 Bad Request at the pre-check stage. Don't let it reach your application layer at all.

7. Rate Limit and Cap Resources

Uncapped APIs are an invitation to abuse - whether from bots, scrapers, or a badly-written client stuck in a retry loop.

Set hard limits at the API Gateway level:

  • Request rate: e.g., 100 requests per minute per client
  • Payload size: e.g., 1 MB maximum request body
  • Timeout: e.g., 30 seconds before the request is dropped

Requests that exceed these limits should be blocked with a 429 Too Many Requests response. Combine rate limiting with exponential backoff guidance in your error responses, so legitimate clients degrade gracefully.

Rate limiting also protects you from the less obvious threat: a single runaway job exhausting your compute budget.

8. Defend Sensitive Business Flows

Some endpoints carry outsized risk: login, checkout, signup, OTP verification. These are high-value targets for automated abuse - credential stuffing, account enumeration, payment fraud.

Layered defenses for these flows should include:

  • Velocity rules - block accounts or IPs attempting more than N actions in a time window
  • Idempotency keys - prevent duplicate transaction submissions
  • CAPTCHA - challenge suspicious sessions
  • Step-up MFA - require a second factor for high-risk actions, even within an authenticated session

The goal is to make automated abuse economically unviable while keeping the experience smooth for real users.

9. Control Outbound and Third-Party Calls

Inbound requests aren't the only attack vector. Server-Side Request Forgery (SSRF) and malicious redirects can turn your API into a proxy for attackers.

All outbound traffic from your API should pass through an egress gate that:

  • Allowlists approved partner APIs and domains
  • Blocks redirects to unknown hosts
  • Rejects requests targeting internal IP ranges (like 169.254.x.x - AWS metadata endpoints)
  • Validates and sanitizes responses from third-party APIs before processing them

If your API fetches external URLs based on user input, this is especially critical. Never make unauthenticated requests to arbitrary destinations.

10. Harden Config and Error Handling

Default configurations are the enemy of security. Every framework, every runtime, every cloud service ships with defaults optimized for ease of use - not safety.

Harden your deployment by:

  • Deny by default: only explicitly allow what's needed - routes, methods, origins
  • Lock HTTP methods: if an endpoint only accepts GET, reject POST, PUT, and DELETE
  • Enforce strict CORS: whitelist specific origins, don't use * in production
  • Disable debug mode: stack traces and internal error details are a gift to attackers

Your error messages should be generic to external callers. Log the full detail server-side, but never expose internal paths, database errors, or stack traces in API responses.

11. Inventory APIs and Versions

You can't secure what you don't know exists. Shadow APIs - endpoints that are deployed but undocumented and unmonitored - are a persistent blind spot in large organizations.

Maintain an API registry that tracks:

  • Every endpoint and its current status (active, sunset, deprecated)
  • Every version (/v1, /v2, etc.) and its support lifecycle
  • Every shadow or experimental API flagged for review

Sunsetting old API versions is as important as shipping new ones. An old /v1/users endpoint still running in production, unmaintained and unpatched, is a liability. Deprecation should follow a clear timeline with client notifications.

12. Log, Detect, and Respond

Logging is not a nice-to-have - it's your incident response lifeline.

Every API should emit structured logs covering:

  • Authentication decisions (successes and failures)
  • Admin actions
  • Configuration changes
  • Anomalies and errors
  • What should never appear in logs: secrets, tokens, or PII (Personally Identifiable Information)

Feed these logs into a SIEM (Security Information and Event Management) system that generates real-time alerts. A spike in 401 Unauthorized responses, for example, is an early signal of a credential stuffing attack.

The goal isn't just to detect breaches - it's to detect them fast enough to respond before significant damage is done.

Putting It All Together

No single one of these practices is a silver bullet. API security is defense in depth: multiple layers, each assuming the others might fail.

Start with an honest audit of your current stack against each of these areas. Prioritize by severity: BOLA issues and unauthenticated endpoints first, operational hardening next, observability alongside everything else.

Security isn't a feature you ship once. It's a discipline you maintain continuously.

Top comments (0)