Per-user rate limiting has been implemented to enforce different rate limits based on user roles and authentication status. This ensures fair resource allocation across different user tiers while protecting the API from abuse.
File: src/config/per-user-rate-limit.config.ts
Service that manages per-user rate limit configurations based on user roles:
- Anonymous Users: IP-based tracking with configurable limits
- Regular Users: Standard authenticated user limits
- Verifiers: Higher limits due to more frequent API operations
- Admins: Complete bypass of rate limiting
Configuration is sourced from environment variables, allowing runtime customization without code changes.
File: src/common/guards/throttler.guard.ts
Enhanced ThrottlerGuard that:
- Extracts user role information from JWT tokens and request context
- Tracks users by unique ID (Stellar address or database ID)
- Falls back to IP-based tracking for anonymous users
- Applies role-specific rate limits dynamically
- Bypasses rate limiting for admin users
Key methods:
shouldSkip(): Returns true for admin users to bypass rate limitinggetTracker(): Extracts user identity for per-user trackinggetThrottleMetadata(): Applies role-based rate limits dynamicallygetDefaultMetadata(): Provides fallback limits from configuration
| User Type | Default Limit | Default TTL | Configurable |
|---|---|---|---|
| Anonymous (IP) | 50 | 60s | Yes |
| Regular User | 100 | 60s | Yes |
| Verifier | 200 | 60s | Yes |
| Admin | Unlimited | N/A | No |
Users are tracked using a composite key format:
- Authenticated Users:
user:{userId}- Tracked by unique user ID - Anonymous Users:
ip:{ipAddress}- Tracked by IP address
This ensures each user has their own independent rate limit counter.
# Anonymous user limits (IP-based tracking)
RATE_LIMIT_ANONYMOUS_LIMIT=50
RATE_LIMIT_ANONYMOUS_TTL=60
# Regular authenticated user limits
RATE_LIMIT_USER_LIMIT=100
RATE_LIMIT_USER_TTL=60
# Verifier user limits
RATE_LIMIT_VERIFIER_LIMIT=200
RATE_LIMIT_VERIFIER_TTL=60
# Auth endpoint limits for authenticated users
RATE_LIMIT_AUTH_USER_LIMIT=30
RATE_LIMIT_AUTH_USER_TTL=60All limits are configurable via environment variables. If not specified, sensible defaults are used.
Each user has a completely independent rate limit counter. One user hitting their limit does not affect other users.
// Example: Two users making simultaneous requests
User A: user:stellar_address_A → 100 requests/minute limit
User B: user:stellar_address_B → 100 requests/minute limit
// Each user can make 100 requests independentlyLimits are applied based on user role, allowing different tiers of service:
if (userRole === UserRole.ADMIN) {
// Admin users bypass rate limiting completely
return true; // Skip throttling
} else if (userRole === UserRole.VERIFIER) {
// Verifiers get higher limits: 200 req/minute
} else if (userRole === UserRole.USER) {
// Regular users get standard limits: 100 req/minute
} else {
// Anonymous users get conservative limits: 50 req/minute
}User role is extracted from:
- Request context (
req.user.role) - Set by authentication guards - JWT token payload (
payload.role) - Fallback for token verification - Falls back to 'anonymous' if no user information is found
Rate limit information is exposed via standard HTTP headers:
X-RateLimit-Limit: Maximum number of requests allowedX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when the rate limit resetsRetry-After: Seconds to wait before retrying (on 429 response)
Comprehensive tests verify:
- Default limits are enforced for anonymous users
- Per-user limits work correctly for authenticated users
- Different users have independent limit counters
- Verifiers have appropriate higher limits
- Admins bypass rate limiting entirely
- Admin users can make unlimited requests
- Rate-limited responses include Retry-After header
Run tests with:
npm run test:e2e✅ Per-user limits work
- Each user has independent rate limit tracking
- Limits are applied based on user role
- Anonymous users tracked by IP address
- Authenticated users tracked by unique ID
✅ Configured throttler for users
- ThrottlerGuard extended with per-user logic
- Role-based configuration service created
- Dynamic limit application per request
✅ User-based filters
- User identification and extraction implemented
- Role detection from JWT and request context
- Fallback to IP-based tracking for anonymous
✅ Limits tested
- E2E tests verify per-user rate limiting
- Tests confirm admin bypass functionality
- Tests verify separate counters per user
-
Admin Bypass: Admins are completely bypassed from rate limiting. Only trusted admin addresses (from
ADMIN_ADDRESSESenv var) are treated as admins. -
User Identification: User identification is derived from:
- Request context (set by authenticated middleware)
- JWT token verification (with cryptographic signature validation)
-
IP Spoofing: Anonymous users are tracked by IP, with support for:
- X-Forwarded-For header (for proxies)
- Request IP address fallback
- Proper parsing of comma-separated proxy chains
-
Rate Limit Evasion: Each user gets a unique counter key, making it difficult to distribute requests across multiple accounts to bypass limits.
Potential improvements:
- Per-endpoint rate limits (different limits for different routes)
- Dynamic rate limit adjustment based on system load
- Rate limit upgrade for premium users
- Distributed rate limiting for multi-instance deployments
- Rate limit analytics and monitoring dashboard
This document is the canonical reference for per-user rate limiting. The previous loose root-level report (RATE_LIMITING_COMPLETION_REPORT.md) was consolidated here.
src/config/per-user-rate-limit.config.ts— per-user rate limit configuration
src/common/guards/throttler.guard.ts— per-user limit trackingsrc/app.module.ts— throttler wiring.env.example— documented theRATE_LIMIT_*variablestest/common/rate-limiting.e2e-spec.ts— e2e coverage
# Run per-user rate limiting tests
npm run test:e2e -- --testPathPattern=rate-limiting
# Expected results:
# - Anonymous (IP-based) users hit their limit and receive 429
# - Authenticated users get higher, role-based limits
# - X-RateLimit-* headers are present on throttled responsesRATE_LIMIT_ANONYMOUS_LIMIT=50
RATE_LIMIT_USER_LIMIT=100
RATE_LIMIT_VERIFIER_LIMIT=200
RATE_LIMIT_AUTH_USER_LIMIT=30Monitor rate-limit health via HTTP 429 counts and X-RateLimit-* headers, then tune limits based on system performance and API usage patterns.
- ✅ Per-user limits work (authenticated users are isolated from one another)
- ✅ Throttler configured for users with role-based tiers
- ✅ User-based filters in place (anonymous vs authenticated vs verifier vs auth endpoints)
- ✅ Comprehensive tests cover the limit tiers