diff --git a/astro.config.mjs b/astro.config.mjs index b3e2cc9..a87ae12 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -43,6 +43,7 @@ export default defineConfig({ { label: 'Email Service', link: '/api-server/features/email-service' }, { label: 'Data Management', link: '/api-server/features/data-management-api' }, { label: 'RBAC', link: '/api-server/features/rbac' }, + { label: 'Rate Limiting', link: '/api-server/features/rate-limiting' }, ], }, { diff --git a/src/content/docs/api-server/architecture/error-handling.mdx b/src/content/docs/api-server/architecture/error-handling.mdx index e64a1c7..de7dc58 100644 --- a/src/content/docs/api-server/architecture/error-handling.mdx +++ b/src/content/docs/api-server/architecture/error-handling.mdx @@ -34,6 +34,7 @@ The following table lists the most common error codes and their corresponding HT | `403` | `forbidden` | The authenticated user does not have the necessary permissions to perform the requested action. | | `404` | `notFound` | The requested resource (e.g., an item with a specific ID) could not be found. | | `409` | `conflict` | The request could not be completed due to a conflict with the current state of the resource. | +| `429` | `forbidden` | The request was rejected because the client has exceeded the rate limit. | | `500` | `serverError` | A generic error occurred on the server. | | `500` | `operationFailed` | A specific, known operation failed on the server for an unexpected reason. | | `500` | `unknownError` | An unexpected and unhandled error occurred on the server. | diff --git a/src/content/docs/api-server/architecture/middleware.mdx b/src/content/docs/api-server/architecture/middleware.mdx index e4d1709..dcfd7a6 100644 --- a/src/content/docs/api-server/architecture/middleware.mdx +++ b/src/content/docs/api-server/architecture/middleware.mdx @@ -26,6 +26,7 @@ Here is the typical execution order for a request to a protected data endpoint l 3. **Data Route Middleware (`/routes/api/v1/data/_middleware.dart`)** - **Require Authentication:** Checks if a `User` object exists in the context. If not, it immediately aborts the request with a `401 Unauthorized` error. + - **Rate Limiting:** If the user is not an admin, it applies a rate limit based on the user's ID. If the limit is exceeded, it aborts with a `429 Too Many Requests` error. - **Model Validation:** Validates the `?model=` query parameter and injects the corresponding `ModelConfig` into the context. - **Authorization:** Checks if the authenticated user has the required permissions to perform the requested action on the specified model. If not, it aborts with a `403 Forbidden` error. diff --git a/src/content/docs/api-server/features/index.mdx b/src/content/docs/api-server/features/index.mdx index 82f28b1..ac9d1cd 100644 --- a/src/content/docs/api-server/features/index.mdx +++ b/src/content/docs/api-server/features/index.mdx @@ -24,4 +24,8 @@ The API server is packed with features designed for a modern, scalable news appl Explore the granular permission system that secures the API. [Read more →](/docs/api-server/features/rbac) + + Learn how the API prevents abuse with built-in request rate limiting. + [Read more →](/docs/api-server/features/rate-limiting) + diff --git a/src/content/docs/api-server/features/rate-limiting.mdx b/src/content/docs/api-server/features/rate-limiting.mdx new file mode 100644 index 0000000..ba566c1 --- /dev/null +++ b/src/content/docs/api-server/features/rate-limiting.mdx @@ -0,0 +1,46 @@ +--- +title: 'Feature: Rate Limiting' +description: An overview of the API server's built-in rate limiting to prevent abuse and ensure stability. +--- + +import { Aside } from '@astrojs/starlight/components'; + +To ensure the stability and security of the API, the server includes a built-in rate-limiting feature. This system automatically tracks the number of requests from a given source and blocks further requests if they exceed a configured limit within a specific time window. + +This is crucial for preventing abuse, such as brute-force attacks on the authentication endpoints or overly aggressive polling of the data API. + +### How It Works + +The rate-limiting mechanism is implemented as a middleware that runs on specific routes. It uses the client's IP address as the primary identifier for tracking requests. + +There are two distinct rate-limiting configurations applied to different parts of the API: + +1. **Sensitive Endpoint Limiting:** + - **Target:** The `/api/v1/auth/request-code` endpoint. + - **Purpose:** This endpoint is more sensitive as it triggers an email to be sent. The rate limit here is intentionally strict to prevent spamming users with verification codes. + - **Default Limit:** 3 requests per 24 hours. + +2. **General Data API Limiting:** + - **Target:** All endpoints under `/api/v1/data`. + - **Purpose:** This provides a generous limit for general application usage while still protecting the server from excessively frequent requests from a single client. + - **Default Limit:** 1000 requests per 60 minutes. + + + +### Configuration + +These limits are configurable via environment variables, allowing you to adjust them for your specific production needs. For details, see the [Configure Environment Variables](/docs/api-server/guides/configure-environment-variables) guide. + +### Error Response + +When a client exceeds a rate limit, the API will respond with an HTTP `429 Too Many Requests` status code and the following error payload: + +```json +{ + "error": { + "code": "forbidden", + "message": "You have made too many requests. Please try again later." + } +} diff --git a/src/content/docs/api-server/guides/configure-environment-variables.mdx b/src/content/docs/api-server/guides/configure-environment-variables.mdx index a86a841..66282fe 100644 --- a/src/content/docs/api-server/guides/configure-environment-variables.mdx +++ b/src/content/docs/api-server/guides/configure-environment-variables.mdx @@ -111,7 +111,11 @@ These variables have default values but can be customized for your environment. #### `JWT_EXPIRY_HOURS` The duration, in hours, for which a JWT is valid. -- **Default:** `1` (1 hour) +- **Default:** `720` (1 month) + + #### `CORS_ALLOWED_ORIGIN` The specific origin URL of your web client (e.g., the Flutter Web Dashboard) that is allowed to make requests to this API. This is **required for production** to prevent Cross-Origin Resource Sharing (CORS) errors. @@ -125,3 +129,21 @@ For more details on CORS, see the [Configure CORS](/docs/api-server/guides/confi The base URL for the SendGrid API. - **Default:** `https://api.sendgrid.com` - **EU Accounts:** If your SendGrid account is based in the EU, you may need to set this to `https://api.eu.sendgrid.com`. + +#### `RATE_LIMIT_REQUEST_CODE_LIMIT` +The number of times a user can request a sign-in code within the defined window. +- **Default:** `3` + + + +#### `RATE_LIMIT_REQUEST_CODE_WINDOW_HOURS` +The time window, in hours, for the sign-in code request limit. +- **Default:** `24` + +#### `RATE_LIMIT_DATA_API_LIMIT` +The number of general data API requests a user can make within the defined window. +- **Default:** `1000` + +#### `RATE_LIMIT_DATA_API_WINDOW_MINUTES`