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.

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

MethodSecurityUse Case
API KeysBasicPublic APIs, rate limiting
Basic AuthLow (over HTTPS)Simple internal APIs
JWTGoodStateless auth, SPAs
OAuth 2.0ExcellentThird-party access, delegated auth
mTLSExcellentService-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:

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

#VulnerabilityPrevention
1Broken Object Level AuthorizationAlways check ownership/permissions
2Broken AuthenticationUse proven auth libraries, MFA
3Broken Object Property Level AuthValidate all properties, allowlists
4Unrestricted Resource ConsumptionRate limiting, quotas
5Broken Function Level AuthorizationRBAC, verify permissions per endpoint
6Unrestricted Access to Sensitive FlowsCAPTCHAs, anomaly detection
7Server Side Request ForgeryValidate URLs, allowlist destinations
8Security MisconfigurationHardened defaults, security headers
9Improper Inventory ManagementAPI documentation, version control
10Unsafe Consumption of APIsValidate third-party responses

7. Security Testing

7.1 Tools for API Security Testing

# 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

Should I use JWT or session cookies?
For traditional web apps, session cookies with HttpOnly, Secure, SameSite flags are often simpler and more secure. JWTs excel in stateless architectures, mobile apps, and microservices where you need to validate tokens without database lookups.
How do I implement rate limiting?
Use algorithms like Token Bucket or Sliding Window Log. Implement at multiple levels: per-user, per-IP, per-endpoint. Return 429 Too Many Requests with Retry-After header. Consider using API gateways which provide this built-in.

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