Key Takeaways
- Always use HTTPS; never expose APIs over plain HTTP.
- Implement proper authentication (OAuth 2.0, JWT) and authorization.
- Validate and sanitize all input; never trust client data.
- Rate limiting prevents abuse and DDoS attacks.
- Log all API access for security monitoring.
- Follow OWASP API Security Top 10 guidelines.
Table of Contents
1. API Security Overview
APIs are the backbone of modern applications, enabling communication between services, mobile apps, and third-party integrations. However, APIs are also prime attack targets—they expose business logic and data directly, often bypassing traditional web application protections.
API security requires a defense-in-depth approach: secure transport, strong authentication, proper authorization, input validation, rate limiting, logging, and continuous testing.
2. Authentication Methods
| Method | Security | Use Case |
|---|---|---|
| API Keys | Basic | Public APIs, rate limiting |
| Basic Auth | Low (over HTTPS) | Simple internal APIs |
| JWT | Good | Stateless auth, SPAs |
| OAuth 2.0 | Excellent | Third-party access, delegated auth |
| mTLS | Excellent | Service-to-service, B2B |
2.1 API Keys
Simple but limited. API keys identify the calling application, not the user. They should be rotated regularly and never exposed in client-side code.
# API Key in header (preferred)
Authorization: ApiKey sk_live_abc123
# Never in URL (logged, cached, leaked via referer)
GET /api/users?api_key=sk_live_abc123 # BAD!
2.2 OAuth 2.0
OAuth 2.0 is the standard for delegated authorization. Different grant types serve different use cases:
- Authorization Code + PKCE: SPAs, mobile apps (most secure for clients)
- Client Credentials: Machine-to-machine authentication
- Implicit: Deprecated, don't use
- Password: Legacy only, avoid if possible
3. Authorization & Access Control
3.1 Broken Object Level Authorization (BOLA)
The #1 API vulnerability. Always verify the authenticated user has access to the requested resource.
# VULNERABLE: No ownership check
GET /api/orders/12345
# Any authenticated user can access any order
# SECURE: Verify ownership
def get_order(order_id, current_user):
order = Order.find(order_id)
if order.user_id != current_user.id:
return 403, "Forbidden"
return order
3.2 Role-Based Access Control (RBAC)
# Express.js middleware example
const requireRole = (roles) => (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
app.delete('/api/users/:id', requireRole(['admin']), deleteUser);
4. JWT Security
4.1 JWT Best Practices
# Secure JWT configuration
- Algorithm: RS256 or ES256 (asymmetric, not HS256)
- Expiration: Short-lived tokens (15 min - 1 hour)
- Audience: Validate 'aud' claim
- Issuer: Validate 'iss' claim
- No sensitive data in payload (it's base64, not encrypted)
JWT Vulnerabilities
Algorithm Confusion: Never allow alg:none or switching algorithms
Weak Secrets: HS256 secrets must be 256+ bits of randomness
No Expiration: Always set and validate exp claim
Token in URL: Never pass tokens in query strings
4.2 Refresh Token Pattern
# Access Token: Short-lived (15 min)
{
"sub": "user123",
"exp": 1703001600, // 15 minutes
"scope": "read write"
}
# Refresh Token: Longer-lived, stored securely
# Used only to obtain new access tokens
# Can be revoked server-side
5. Input Validation
5.1 Validation Strategies
// Schema validation with Joi (Node.js)
const schema = Joi.object({
email: Joi.string().email().required(),
age: Joi.number().integer().min(0).max(150),
role: Joi.string().valid('user', 'admin'),
password: Joi.string().min(12).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
});
const { error, value } = schema.validate(req.body);
if (error) return res.status(400).json({ error: error.details });
5.2 Preventing Injection
# SQL Injection - Use parameterized queries
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# Not this:
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") # VULNERABLE
# NoSQL Injection - Validate types
if (typeof req.body.username !== 'string') {
return res.status(400).json({ error: 'Invalid input' });
}
6. OWASP API Security Top 10
| # | Vulnerability | Prevention |
|---|---|---|
| 1 | Broken Object Level Authorization | Always check ownership/permissions |
| 2 | Broken Authentication | Use proven auth libraries, MFA |
| 3 | Broken Object Property Level Auth | Validate all properties, allowlists |
| 4 | Unrestricted Resource Consumption | Rate limiting, quotas |
| 5 | Broken Function Level Authorization | RBAC, verify permissions per endpoint |
| 6 | Unrestricted Access to Sensitive Flows | CAPTCHAs, anomaly detection |
| 7 | Server Side Request Forgery | Validate URLs, allowlist destinations |
| 8 | Security Misconfiguration | Hardened defaults, security headers |
| 9 | Improper Inventory Management | API documentation, version control |
| 10 | Unsafe Consumption of APIs | Validate third-party responses |
7. Security Testing
7.1 Tools for API Security Testing
- Burp Suite: Manual and automated API testing
- OWASP ZAP: Open-source security scanner
- Postman: Collection testing with security checks
- Nuclei: Template-based vulnerability scanning
# Test for BOLA with curl
# Authenticate as User A, try to access User B's resources
curl -H "Authorization: Bearer USER_A_TOKEN" \
https://api.example.com/users/USER_B_ID
# Should return 403, not 200
8. Frequently Asked Questions
Conclusion
API security requires continuous attention. Implement strong authentication and authorization, validate all input, follow OWASP guidelines, and test regularly. Remember that APIs are often the most direct path to your data—secure them accordingly.
Continue Learning:
OAuth 2.0 Guide
JWT Security