API Security Best Practices Every Developer Should Know
Master API security with practical best practices covering authentication, authorization, input validation, rate limiting, and monitoring to protect your applications.
API Security Best Practices Every Developer Should Know
APIs are the backbone of modern software. They connect microservices, power mobile apps, integrate third-party platforms, and expose functionality to partners and customers. They are also one of the most attacked surfaces in any application. The OWASP API Security Top 10 highlights that broken authentication, broken object-level authorization, and excessive data exposure account for a staggering number of real-world breaches.
The challenge is that many developers build APIs with functionality as the priority and security as an afterthought. This guide provides practical, implementable API security practices that every development team should adopt from day one.
Authentication: Getting Identity Right
Authentication verifies who is making the request. Getting this wrong means everything else in your security model falls apart.
Use OAuth 2.0 and OpenID Connect
For user-facing APIs, implement OAuth 2.0 with OpenID Connect (OIDC). Do not invent your own authentication protocol. Use a proven identity provider like Auth0, Okta, AWS Cognito, or Keycloak.
Key implementation rules:
- Issue short-lived access tokens (15 to 60 minutes) with refresh tokens for session continuity
- Use the authorization code flow with PKCE for single-page applications and mobile apps - never the implicit flow
- Validate JWTs on every request by checking the signature, issuer, audience, and expiration
- Store signing keys securely and rotate them on a defined schedule
- Never pass tokens in URL query parameters - use the Authorization header
API Keys Are Not Authentication
API keys identify the calling application, not the user. They are useful for rate limiting and usage tracking, but they should not be your only security layer. Always combine API keys with proper authentication for sensitive operations.
API key management essentials:
- Generate cryptographically random keys of sufficient length (at least 32 characters)
- Support key rotation without downtime by allowing multiple active keys per client
- Transmit keys in headers, never in URLs (URLs appear in logs and browser history)
- Implement different key scopes for different access levels
- Provide a self-service key revocation mechanism
Authorization: Controlling What Users Can Access
Authentication tells you who someone is. Authorization determines what they are allowed to do. Broken Object Level Authorization (BOLA) is the number one API security vulnerability according to OWASP, and it is alarmingly common.
Implement Object-Level Authorization
Every API endpoint that accesses a resource must verify that the authenticated user has permission to access that specific resource. This is not a middleware problem - it must be enforced at the application logic level.
// Dangerous - no authorization check
GET /api/invoices/12345
// Secure - verify ownership before returning data
GET /api/invoices/12345
-> Verify that the authenticated user owns invoice 12345
-> Return 404 (not 403) if they do not, to prevent enumeration
Common BOLA patterns to watch for:
- Sequential integer IDs that allow enumeration (use UUIDs instead)
- Endpoints that accept a user ID parameter and return that user's data without verifying the caller's identity matches
- Admin endpoints that differ from user endpoints only by URL path, with no role enforcement
- Bulk endpoints that do not filter results based on the caller's permissions
Enforce Function-Level Authorization
Beyond object access, verify that users have permission to perform specific actions. A regular user should not be able to call administrative endpoints just because they know the URL.
- Define clear roles and permissions for your API
- Enforce role checks at the controller or middleware level
- Use an allowlist approach - deny by default, explicitly grant access
- Audit your routes regularly to ensure every endpoint has appropriate authorization
Input Validation and Data Handling
Never trust client input. Every piece of data that enters your API is a potential attack vector.
Validate Everything
- Define strict schemas for all request bodies using JSON Schema, Zod, Joi, or your framework's validation library
- Validate data types, lengths, ranges, and formats
- Reject requests that include unexpected fields (do not silently ignore them)
- Validate path parameters and query strings, not just request bodies
- Use parameterized queries for all database operations - no exceptions
- Sanitize output to prevent stored XSS when API data is rendered in browsers
Control Response Data
Excessive data exposure is another top API vulnerability. APIs frequently return entire database objects when the client only needs a few fields.
Best practices for response data:
- Define explicit response schemas for each endpoint - never return raw database objects
- Remove internal identifiers, timestamps, and metadata that clients do not need
- Strip sensitive fields (password hashes, internal flags, audit data) from all responses
- Use different response schemas for different authorization levels (admin vs. regular user)
- Implement field-level encryption for particularly sensitive data in transit
Rate Limiting and Throttling
Without rate limiting, your API is vulnerable to brute-force attacks, credential stuffing, denial of service, and scraping.
Implement Layered Rate Limiting
Apply rate limits at multiple levels:
- Global rate limit - Maximum requests per IP address per time window
- Authenticated rate limit - Maximum requests per authenticated user or API key
- Endpoint-specific limits - Stricter limits on sensitive endpoints (login, password reset, payment processing)
- Resource-based limits - Limits on expensive operations (report generation, bulk exports)
Implementation guidelines:
- Return 429 (Too Many Requests) with a Retry-After header when limits are exceeded
- Include rate limit headers in every response:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset - Use sliding window algorithms rather than fixed windows to prevent burst abuse at window boundaries
- Apply stricter limits to unauthenticated requests
- Consider using a dedicated rate limiting service (Redis-based, API gateway, or cloud-native)
Protect Authentication Endpoints Specifically
Login and password reset endpoints deserve special attention:
- Implement progressive delays after failed attempts (1 second, 2 seconds, 4 seconds, etc.)
- Lock accounts temporarily after a threshold of failed attempts
- Use CAPTCHA challenges after repeated failures
- Return generic error messages - do not reveal whether the username or password was incorrect
- Log all authentication failures for monitoring and analysis
Monitoring, Logging, and Incident Detection
You cannot protect what you cannot see. Comprehensive API monitoring enables rapid detection and response to attacks.
Log Security-Relevant Events
Every API should log these events with sufficient detail:
- All authentication attempts (successes and failures) with source IP and user agent
- Authorization failures (users attempting to access resources they do not own)
- Input validation failures (potential injection attempts)
- Rate limit violations
- Changes to sensitive resources (user roles, permissions, financial data)
- API key creation, rotation, and revocation
Logging best practices:
- Use structured logging (JSON) for easy parsing and analysis
- Never log sensitive data - tokens, passwords, credit card numbers, or PII
- Include correlation IDs to trace requests across microservices
- Ship logs to a centralized platform (Datadog, Splunk, ELK, or CloudWatch)
- Set up alerts for anomalous patterns (spike in 401 errors, unusual geographic access, high error rates)
Implement API Threat Detection
Beyond basic logging, consider API-specific threat detection:
- Monitor for credential stuffing patterns (many failed logins from distributed IPs)
- Detect BOLA attempts (users systematically accessing sequential resource IDs)
- Identify data exfiltration patterns (abnormally large response sizes or high request volumes)
- Track API usage patterns and alert on significant deviations from baseline behavior
Secure Your API Development Lifecycle
Security should be embedded in how you build APIs, not bolted on after deployment.
Development practices:
- Use API specification formats (OpenAPI/Swagger) as the source of truth for validation
- Run automated security tests in CI/CD (OWASP ZAP, Nuclei, custom test suites)
- Conduct security-focused code reviews for all API changes
- Maintain an up-to-date API inventory - undocumented endpoints are unprotected endpoints
- Deprecate and remove old API versions on a defined timeline
- Use TLS 1.2 or 1.3 for all API traffic with no exceptions