API Security Best Practices
Protect your APIs from the OWASP API Top 10 and common attack patterns. Essential security practices for REST and GraphQL APIs.
Quick Wins
OWASP API Security Top 10
Broken Object Level Authorization
APIs expose endpoints handling object IDs without proper authorization checks
Prevention: Implement proper authorization checks for every object access. Verify user ownership before returning data.
Broken Authentication
Weak authentication mechanisms allow attackers to compromise tokens or exploit implementation flaws
Prevention: Use standard auth protocols (OAuth 2.0), enforce strong passwords, implement MFA, secure token storage.
Broken Object Property Level Authorization
Exposing sensitive object properties or allowing mass assignment
Prevention: Define explicit allowlists for returnable/writable properties. Never expose internal properties.
Unrestricted Resource Consumption
No limits on API calls, file uploads, or query complexity leads to DoS
Prevention: Implement rate limiting, pagination, timeouts, and resource quotas on all endpoints.
Broken Function Level Authorization
Missing authorization checks on admin functions or sensitive operations
Prevention: Implement consistent authorization at function level. Default deny for admin endpoints.
Authentication Best Practices
JWT Token Security
// Storing secrets in JWT
{ "userId": 123, "apiKey": "sk_live_xxx" }
// No expiration
jwt.sign(payload, secret)
// Using alg: none
jwt.sign(payload, '', { algorithm: 'none' })// Minimal claims
{ "sub": "user_123", "exp": 1234567890 }
// Short expiration + refresh tokens
jwt.sign(payload, secret, {
algorithm: 'RS256',
expiresIn: '15m'
})API Key Security
- Generate cryptographically secure random keys (256+ bits)
- Store hashed keys, not plaintext (compare hashes on auth)
- Support key rotation without breaking clients
- Implement scoped keys with minimal permissions
- Log key usage for audit trails
Input Validation
Schema Validation
// Using Zod for type-safe validation
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
age: z.number().int().min(13).max(120).optional(),
});
// In your API handler
const result = createUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ error: 'Invalid input' });
}Common Validation Rules
- Validate data types strictly
- Enforce string length limits
- Sanitize special characters
- Reject unexpected fields
- Validate URL parameters
- Check content-type headers
Rate Limiting & Throttling
Implement rate limiting to prevent abuse, brute force attacks, and DoS:
| Endpoint Type | Suggested Limit | Reason |
|---|---|---|
| Login / Auth | 5/min per IP | Prevent brute force |
| Password Reset | 3/hour per email | Prevent enumeration |
| General API | 100/min per user | Fair usage |
| Search / Heavy | 20/min per user | Resource protection |
Return 429 Too Many Requests with Retry-After header when limits are exceeded.
Frequently Asked Questions
Should I use API keys or OAuth for authentication?
Use OAuth 2.0 for user-facing applications and API keys for server-to-server communication. For public APIs, consider supporting both with appropriate scoping.
How do I handle authorization for different user roles?
Implement role-based (RBAC) or attribute-based (ABAC) access control. Check permissions at both route and object level. Never rely solely on frontend hiding features.
Is GraphQL more secure than REST?
Neither is inherently more secure. GraphQL has unique concerns (query depth, batching attacks) while REST has its own (IDOR, verb tampering). Both require proper authentication, authorization, and input validation.
How should I handle API versioning for security patches?
Use URL or header versioning. When patching security issues, backport to all supported versions. Have a clear deprecation policy that encourages upgrades.
Get Starter Scan
Find authentication bypasses, authorization issues, and input validation problems in your API.
Get Starter ScanRelated Resources
Last updated: January 2025