This document describes the rate limiting strategy implemented for the MyFans API.
Rate limiting is enforced globally using @nestjs/throttler to protect against abuse, brute-force attacks, and ensure fair usage across all API endpoints.
| Tier | Limit | TTL | Use Case |
|---|---|---|---|
short |
10 requests | 60 seconds | Default short window |
medium |
50 requests | 60 seconds | Authenticated user operations |
long |
100 requests | 60 seconds | General API endpoints (default) |
| Auth throttle | 5 requests | 60 seconds | Login/register (strict) |
| Exempt | Unlimited | N/A | Health check endpoints |
These endpoints are exempt from rate limiting and can be accessed without restrictions:
GET /v1/health- Basic health checkGET /v1/health/db- Database healthGET /v1/health/redis- Redis healthGET /v1/health/soroban- Soroban RPC healthGET /v1/health/soroban-contract- Soroban contract healthGET /v1/health/queue-metrics- Queue metrics
Rate limited to prevent brute-force attacks:
POST /v1/auth/login- 5 requests per minutePOST /v1/auth/register- 5 requests per minute
Rate limited to prevent abuse while allowing public access:
GET /v1/creators- Search creators: 100 requests per minuteGET /v1/creators/plans- List all plans: 100 requests per minuteGET /v1/creators/:address/plans- List creator plans: 100 requests per minute
Default rate limit of 100 requests per minute applies.
When a request is rate limited, the following headers are included in the response:
Retry-After: <seconds>
X-RateLimit-Limit: <limit>
X-RateLimit-Remaining: <remaining>
X-RateLimit-Reset: <timestamp>
When a client exceeds the rate limit, they will receive a 429 Too Many Requests response:
{
"statusCode": 429,
"message": "ThrottlerException: Too Many Requests"
}Rate limiting is configured in backend/src/app.module.ts:
ThrottlerModule.forRoot([
{ name: 'short', ttl: 60000, limit: 10 },
{ name: 'medium', ttl: 60000, limit: 50 },
{ name: 'long', ttl: 60000, limit: 100 },
]),A custom ThrottlerGuard (backend/src/auth/throttler.guard.ts) extends the NestJS throttler to:
- Exempt health check endpoints from rate limiting
- Apply appropriate rate limits based on route
Individual routes can be configured using the @Throttle() decorator:
@Controller({ path: 'auth', version: '1' })
export class AuthController {
@Post('login')
@Throttle({ short: { limit: 5, ttl: 60000 } })
async login(@Body() body: { address?: string }) {
// ...
}
}The API also sets security headers on all responses:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
To adjust rate limits:
- Global limits: Edit
ThrottlerModule.forRoot()inbackend/src/app.module.ts - Per-route limits: Add or modify
@Throttle()decorators on controller methods - New exempt routes: Update
ThrottlerGuard.isHealthCheckRoute()inbackend/src/auth/throttler.guard.ts
The current implementation uses in-memory rate limiting which works for single-instance deployments.
For multi-instance production deployments, consider using Redis-backed throttling:
// Install: npm install @throttler/redis ioredis
import { RedisStore } from '@throttler/redis';
ThrottlerModule.forRoot([
{
name: 'long',
ttl: 60000,
limit: 100,
storage: new RedisStore({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
}),
},
]),Rate limiting is tested in backend/src/auth/throttler.guard.spec.ts.
Run tests:
cd backend
npm test -- throttler.guard.spec.ts- Implement rate limiting per user/IP
- Add stricter limits for auth endpoints (5 req/min)
- Configure request quotas per endpoint type
- Handle rate limit errors gracefully (429 response)
- Return proper rate limit headers
- Use Redis for distributed rate limiting (recommended for production)
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- X-XSS-Protection enabled
- HSTS header configured
- Content Security Policy (CSP) - future enhancement
- Referrer-Policy - future enhancement
- Log security events (rate limit violations)
- Monitor for suspicious activity
- Set up alerts for repeated violations
- Track API usage patterns