diff --git a/README.md b/README.md index 7e0df90..ddad1c0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The server is responsible for: - notifications, analytics, and moderation workflows - access checks for gated off-chain content -See [Backend Domain Model and Endpoint Boundaries](./docs/architecture/domain-boundaries.md) for a technical overview, [API Versioning](./docs/api-versioning.md) for details on schema versioning, and [API Timeout Configuration](./docs/api-timeouts.md) for timeout defaults and override guidance. +See [Backend Domain Model and Endpoint Boundaries](./docs/architecture/domain-boundaries.md) for a technical overview, [API Versioning](./docs/api-versioning.md) for details on schema versioning, [API Timeout Configuration](./docs/api-timeouts.md) for timeout defaults, and [Rate Limiting Configuration](./docs/rate-limiting.md) for rate limit defaults and guidelines. ## Tech diff --git a/docs/ERROR_CODE_REGISTRY.md b/docs/ERROR_CODE_REGISTRY.md index b53a0fa..f0fabd1 100644 --- a/docs/ERROR_CODE_REGISTRY.md +++ b/docs/ERROR_CODE_REGISTRY.md @@ -396,3 +396,4 @@ Error codes are part of the public API contract and should be treated as stable: - [API Error Handling](./architecture/route-error-mapping.md) - Error handling architecture - [Error Constants](../src/constants/error.constants.ts) - Error code definitions - [API Response Utilities](../src/utils/api-response.utils.ts) - Helper functions for sending errors +- [Rate Limiting](./rate-limiting.md) - Rate limiting configuration and thresholds diff --git a/docs/configuration.md b/docs/configuration.md index eeb9b7d..957c6e6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -496,4 +496,5 @@ const value = envConfig.NEW_CONFIG_VALUE; - [API Versioning](./api-versioning.md) - API version configuration - [Query Debug](./query-normalization-debug.md) - Debug logging configuration +- [Rate Limiting](./rate-limiting.md) - Rate limiting configuration and thresholds - [README](../README.md) - Local setup instructions diff --git a/docs/rate-limiting.md b/docs/rate-limiting.md new file mode 100644 index 0000000..226d9d7 --- /dev/null +++ b/docs/rate-limiting.md @@ -0,0 +1,143 @@ +# Rate Limiting Configuration + +This document outlines the rate limiting mechanisms in place for the Access Layer API, their default thresholds, behavior, and instructions for configuring custom per-endpoint limits. + +## Overview + +The Access Layer server implements rate limiting to protect the system against resource exhaustion, Denial-of-Service (DoS) attacks, brute-force attempts, and scraper activity. + +Rate limiting is implemented using the `express-rate-limit` middleware, which registers a global limiter applied to all incoming API requests (except for health checks and doc serving paths that bypass it or have their own handling). + +- **Middleware Location:** [rate.middleware.ts](file:///c:/Users/PC/Desktop/accesslayer-server/src/middlewares/rate.middleware.ts) +- **Application Setup:** [app.ts](file:///c:/Users/PC/Desktop/accesslayer-server/src/app.ts) (mounted via `app.use(appRateLimit)`) + +--- + +## Default Thresholds + +The default rate limit configuration uses a sliding/fixed window rate limiter based on the client IP address. + +| Environment | Limit (Requests) | Window Size | Units | Description | +| :--- | :--- | :--- | :--- | :--- | +| **Production** | `1,000` | `15` | minutes | Standard rate limit for API consumers | +| **Development** / **Test** | `10,000` | `15` | minutes | Relaxed rate limit to facilitate local testing and manual integration tests | + +The window duration is fixed in code: +- **Default Window:** `15` minutes (`RATE_LIMIT_WINDOW_MS` = `15 * 60 * 1000` milliseconds). +- **Production Limit:** `1,000` requests per window. +- **Development/Test Limit:** `10,000` requests per window. + +--- + +## Standard Rate Limit Headers + +Every successful and failed API response includes standard HTTP headers defined by the IETF draft RFC for rate limiting. These headers allow client applications to dynamically adjust their request rates. + +| Header Name | Type | Description | +| :--- | :--- | :--- | +| `RateLimit-Limit` | Integer | The maximum number of allowed requests in the window. | +| `RateLimit-Remaining` | Integer | The number of remaining requests allowed in the current window. | +| `RateLimit-Reset` | Integer | The time at which the rate limit resets (in Unix epoch seconds). | + +> [!NOTE] +> The legacy headers (e.g. `X-RateLimit-*`) are explicitly disabled (`legacyHeaders: false`) to comply with modern API standards. + +--- + +## Rate-Exceeded Response Behavior + +When a client exceeds the allowed request threshold, the server rejects the request immediately without hitting controllers or the database. + +### Response Metadata + +- **HTTP Status Code:** `429 Too Many Requests` +- **Response Headers:** + - `Retry-After`: The duration in seconds that the client must wait before making another request (e.g., `900` seconds if a client is blocked at the start of a window). + +### Response Body + +The response returns a JSON object following the API error pattern: + +```json +{ + "type": "RATE_LIMIT_EXCEEDED", + "message": "Too many requests, please try again later.", + "retryAfterSeconds": 900, + "timestamp": "2026-05-29T20:00:00.000Z" +} +``` + +- **`type`**: Always returns `'RATE_LIMIT_EXCEEDED'`. +- **`message`**: A human-readable message instructing the client. +- **`retryAfterSeconds`**: Integer representing the remaining seconds of the block. +- **`timestamp`**: ISO-8601 string of the exact date and time the block occurred. + +--- + +## Custom Per-Endpoint Thresholds + +Currently, **all endpoints share the global rate limit**, and there are no custom per-endpoint thresholds configured. + +If you are developing new endpoints that are computationally expensive or susceptible to abuse (e.g., wallet authentication, payment initiation, email dispatch, heavy database query searches), you should define custom limits. + +### Adding a Custom Rate Limiter + +To apply custom rate limits to a specific route or group of routes: + +1. Import the configuration and rate limit helpers. +2. Define a dedicated rate limiter instance. +3. Apply the rate limiter as a route middleware. + +#### Example implementation: + +```typescript +import rateLimit from 'express-rate-limit'; +import { envConfig } from '../../config'; +import { sendRateLimitError } from '../../utils/rate-limit-response.utils'; + +// Define the custom window and limit (e.g., 50 requests per 5 minutes) +const CUSTOM_WINDOW_MS = 5 * 60 * 1000; + +export const expensiveEndpointLimit = rateLimit({ + windowMs: CUSTOM_WINDOW_MS, + max: envConfig.MODE === 'production' ? 50 : 500, + standardHeaders: true, + legacyHeaders: false, + handler: (_req, res) => { + sendRateLimitError(res, CUSTOM_WINDOW_MS / 1000); + }, +}); +``` + +Mount it on your target router: + +```typescript +import { Router } from 'express'; +import { expensiveEndpointLimit } from './expensive.middleware'; + +const router = Router(); + +// Mount custom rate limiter middleware before the controller +router.post('/process-transaction', expensiveEndpointLimit, processTransactionController); + +export default router; +``` + +--- + +## Trust Proxy Configuration + +Because the Access Layer is deployed behind load balancers or reverse proxies (like Nginx or Cloudflare), the server is configured to trust upstream proxy headers to correctly identify client IP addresses: + +```typescript +app.set('trust proxy', 1); +``` + +This prevents the rate limiting middleware from rate limiting the proxy's IP address instead of the client's actual IP address. + +--- + +## Related Documentation + +- [Configuration Guide](./configuration.md) - Loading environment configurations. +- [Error Code Registry](./ERROR_CODE_REGISTRY.md) - Standard API error shapes.