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`