TL;DR
Learn essential best practices and techniques for securing your APIs against common vulnerabilities and threats.
$1
API security is crucial for protecting sensitive data and maintaining the integrity of your applications. This comprehensive guide covers essential practices and implementations for securing your APIs effectively.
$1
$1
`` // Example JWT authentication implementation
import { sign, verify } from 'jsonwebtoken';
import { randomBytes } from 'crypto'; class JWTAuth {
private readonly secretKey: string;
private readonly expiresIn: string;
constructor() {
this.secretKey = process.env.JWT_SECRET || randomBytes(32).toString('hex');
this.expiresIn = '1h';
}
generateToken(payload: Record return sign(payload, this.secretKey, {
expiresIn: this.expiresIn,
algorithm: 'HS256'
});
}
verifyToken(token: string): Record try {
return verify(token, this.secretKey) as Record } catch (error) {
throw new Error('Invalid token');
}
}
refreshToken(token: string): string {
const payload = this.verifyToken(token);
delete payload.exp;
delete payload.iat;
return this.generateToken(payload);
}
}
typescript
`
$1
` // Example OAuth2 implementation
import { OAuth2Client } from 'google-auth-library';
import { randomBytes } from 'crypto'; class OAuth2Auth {
private readonly client: OAuth2Client;
private readonly stateMap: Map redirect: string;
}>;
constructor() {
this.client = new OAuth2Client({
clientId: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
redirectUri: process.env.OAUTH_REDIRECT_URI
});
this.stateMap = new Map();
}
generateAuthUrl(redirect: string): string {
const state = randomBytes(16).toString('hex');
this.stateMap.set(state, {
expires: new Date(Date.now() + 600000), // 10 minutes
redirect
});
return this.client.generateAuthUrl({
access_type: 'offline',
scope: ['profile', 'email'],
state
});
}
async verifyCallback(code: string, state: string): Promise const stateData = this.stateMap.get(state);
if (!stateData || stateData.expires < new Date()) {
throw new Error('Invalid or expired state');
}
const { tokens } = await this.client.getToken(code);
const ticket = await this.client.verifyIdToken({
idToken: tokens.id_token!,
audience: process.env.OAUTH_CLIENT_ID
});
return ticket.getPayload();
}
}
typescript
`
$1
$1
` // Example request validation middleware
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer'; interface ValidationError {
field: string;
errors: string[];
} class RequestValidator {
static async validate dto: new () => T,
data: Record ): Promise const object = plainToClass(dto, data);
const errors = await validate(object as Object);
if (errors.length > 0) {
const validationErrors: ValidationError[] = errors.map(error => ({
field: error.property,
errors: Object.values(error.constraints || {})
}));
throw new Error(JSON.stringify(validationErrors));
}
return object;
}
} // Example DTO
class CreateUserDTO {
@IsString()
@Length(3, 50)
username: string;
@IsEmail()
email: string;
@IsString()
@Matches(/^(?=.[A-Za-z])(?=.\d)[A-Za-z\d]{8,}$/)
password: string;
}
typescript
`
$1
` // Example content security middleware
import { sanitize } from 'dompurify';
import { JSDOM } from 'jsdom'; class ContentSecurity {
private readonly window: any;
private readonly dompurify: any;
constructor() {
this.window = new JSDOM('').window;
this.dompurify = DOMPurify(this.window);
}
sanitizeHtml(content: string): string {
return this.dompurify.sanitize(content, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href']
});
}
validateContentType(contentType: string): boolean {
const allowedTypes = [
'application/json',
'application/x-www-form-urlencoded',
'multipart/form-data'
];
return allowedTypes.includes(contentType);
}
}
typescript
`
$1
$1
` // Example rate limiter implementation
import { Redis } from 'ioredis'; interface RateLimitConfig {
window: number; // Time window in seconds
max: number; // Maximum requests per window
} class RateLimiter {
private readonly redis: Redis;
constructor() {
this.redis = new Redis({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379')
});
}
async isAllowed(
key: string,
config: RateLimitConfig
): Promise const now = Date.now();
const windowStart = now - (config.window * 1000);
// Remove old requests
await this.redis.zremrangebyscore(key, 0, windowStart);
// Count recent requests
const count = await this.redis.zcard(key);
if (count >= config.max) {
return false;
}
// Add new request
await this.redis.zadd(key, now, now.toString());
// Set expiry
await this.redis.expire(key, config.window);
return true;
}
}
typescript
`
$1
` // Example throttling implementation
class ThrottlingManager {
private readonly queues: Map private readonly processing: Set
constructor() {
this.queues = new Map();
this.processing = new Set();
}
async throttle key: string,
operation: () => Promise ): Promise if (this.processing.has(key)) {
return new Promise((resolve, reject) => {
const queue = this.queues.get(key) || [];
queue.push(async () => {
try {
resolve(await operation());
} catch (error) {
reject(error);
}
});
this.queues.set(key, queue);
});
}
this.processing.add(key);
try {
const result = await operation();
// Process queue
const queue = this.queues.get(key) || [];
for (const operation of queue) {
await operation();
}
return result;
} finally {
this.processing.delete(key);
this.queues.delete(key);
}
}
}
typescript
`
$1
$1
` // Example secure error handling
interface ApiError extends Error {
statusCode: number;
code: string;
details?: Record } class ErrorHandler {
static handle(error: Error): ApiError {
// Don't expose internal errors
const sanitizedError: ApiError = {
name: 'ApiError',
message: 'An error occurred',
statusCode: 500,
code: 'INTERNAL_ERROR'
};
if (error instanceof ApiError) {
return {
...sanitizedError,
message: error.message,
statusCode: error.statusCode,
code: error.code
};
}
// Log original error
console.error('Internal Error:', error);
return sanitizedError;
}
}
typescript
`
$1
` // Example secure logging implementation
import { createLogger, format, transports } from 'winston'; class SecureLogger {
private readonly logger: any;
private readonly sensitiveFields: Set
constructor() {
this.sensitiveFields = new Set([
'password',
'token',
'apiKey',
'credit_card'
]);
this.logger = createLogger({
format: format.combine(
format.timestamp(),
format.json(),
format.printf(this.sanitizeLog.bind(this))
),
transports: [
new transports.File({
filename: 'api-security.log',
level: 'info'
})
]
});
}
private sanitizeLog(info: any): string {
const sanitized = { ...info };
this.sanitizeSensitiveData(sanitized);
return JSON.stringify(sanitized);
}
private sanitizeSensitiveData(obj: any): void {
for (const key in obj) {
if (this.sensitiveFields.has(key.toLowerCase())) {
obj[key] = '[REDACTED]';
} else if (typeof obj[key] === 'object') {
this.sanitizeSensitiveData(obj[key]);
}
}
}
}
typescript
`
$1
$1
` openapi: 3.0.0
info:
title: Secure API
version: 1.0.0
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read: Read access
write: Write access
schemas:
Error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: object
security:
- bearerAuth: []
- oauth2: ['read', 'write']
yaml
``Example OpenAPI security configuration
$1
$1
$1
$1
$1
$1
$1
Implementing robust API security is essential for protecting your applications and data. By following these best practices and regularly updating security measures, you can maintain a strong security posture for your APIs.
$1
$1
Here are essential resources for API security:
1. [OWASP API Security Top 10](https://owasp.org/www-project-api-security/) - API security risks and mitigations
2. [OAuth 2.0 Documentation](https://oauth.net/2/) - OAuth 2.0 authorization framework
3. [JWT Best Practices](https://auth0.com/docs/secure/tokens/json-web-tokens) - JSON Web Token security
4. [API Security Checklist](https://github.com/shieldfy/API-Security-Checklist) - Comprehensive security checklist
5. [REST Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html) - OWASP REST security
6. [GraphQL Security](https://graphql.org/learn/best-practices/#security) - GraphQL security best practices
7. [API Gateway Security](https://aws.amazon.com/api-gateway/security/) - AWS API Gateway security
8. [Rate Limiting](https://cloud.google.com/architecture/rate-limiting-strategies-techniques) - Rate limiting strategies
9. [API Authentication](https://developers.google.com/identity/protocols/oauth2) - Google's authentication guide
10. [API Penetration Testing](https://portswigger.net/web-security/api-testing) - API testing guide
11. [Microservices Security](https://microservices.io/patterns/security/) - Security patterns
12. [API Documentation](https://swagger.io/docs/specification/authentication/) - OpenAPI security schemes
These resources provide comprehensive information about securing APIs effectively.
Why This Matters
Understanding the business and technical context helps you make informed decisions rather than blindly following patterns.
Trade-offs to Consider
Every architectural decision involves trade-offs. Consider your specific requirements, team expertise, and scale when evaluating options.
When NOT to Use This
Knowing when a solution doesn't apply is as valuable as knowing when it does. Consider alternatives for your specific situation.
Decision Framework
Use this framework to evaluate whether this approach is right for your use case based on your specific constraints and requirements.