Skip to main content

Rate Limiting

Titan implements Redis-backed rate limiting to protect the API from abuse.

Architecture

How It Works

  1. Request arrives at middleware (HTTP) or hub filter (SignalR)
  2. Match endpoint pattern to find applicable policy
  3. Check token bucket in Redis for remaining requests
  4. Allow or deny based on bucket state
  5. Apply timeout if limit exceeded

Configuration

Configure in appsettings.json:

{
"RateLimiting": {
"Enabled": true,
"DefaultPolicy": "Global",
"MetricsCollectionEnabled": false,
"Policies": {
"Global": {
"Rules": [
{ "RequestsPerWindow": 1000, "WindowSeconds": 60 }
]
},
"Auth": {
"Rules": [
{ "RequestsPerWindow": 10, "WindowSeconds": 60 },
{ "RequestsPerWindow": 100, "WindowSeconds": 3600 }
],
"TimeoutSeconds": 300
},
"Admin": {
"Rules": [
{ "RequestsPerWindow": 1000, "WindowSeconds": 60 }
]
}
},
"EndpointMappings": {
"/api/auth/*": "Auth",
"/api/admin/*": "Admin",
"/hubs/admin*": "AdminHub"
}
}
}

Policies

Policy Structure

interface RateLimitPolicy {
name: string;
rules: RateLimitRule[];
timeoutSeconds?: number;
}

interface RateLimitRule {
requestsPerWindow: number;
windowSeconds: number;
}

Multiple Rules

Policies can have multiple rules. All must pass:

{
"Auth": {
"Rules": [
{ "RequestsPerWindow": 10, "WindowSeconds": 60 }, // 10/min
{ "RequestsPerWindow": 100, "WindowSeconds": 3600 } // 100/hour
],
"TimeoutSeconds": 300
}
}

This means: max 10 requests per minute AND max 100 per hour.

Endpoint Mapping

Endpoints are matched to policies using glob patterns:

PatternMatches
/api/auth/*/api/auth/login, /api/auth/refresh
/api/admin/*/api/admin/users, /api/admin/rate-limit/*
/hubs/*All SignalR hub endpoints

First match wins. Unmatched endpoints use DefaultPolicy.

Client Identification

Rate limits are tracked per-client:

Authentication StateIdentifier
AuthenticatedUser ID (from JWT)
AnonymousIP Address

Timeout Behavior

When a limit is exceeded with TimeoutSeconds configured:

Admin API

Manage rate limiting via the admin dashboard or API:

Get Configuration

GET /api/admin/rate-limit/config
Authorization: Bearer {admin_token}

Enable/Disable

PUT /api/admin/rate-limit/enabled
Content-Type: application/json

{ "enabled": true }

Upsert Policy

PUT /api/admin/rate-limit/policies
Content-Type: application/json

{
"name": "NewPolicy",
"rules": [
{ "requestsPerWindow": 50, "windowSeconds": 60 }
],
"timeoutSeconds": 120
}

Add Endpoint Mapping

POST /api/admin/rate-limit/mappings
Content-Type: application/json

{
"pattern": "/api/custom/*",
"policyName": "NewPolicy"
}

View Metrics

GET /api/admin/rate-limit/metrics

Returns active buckets, timeouts, and request counts.

Metrics

When MetricsCollectionEnabled is true, the system collects:

  • Active buckets: Current token counts per client/endpoint
  • Active timeouts: Clients currently in timeout
  • Request counts: Requests per policy over time

Access via the admin dashboard for real-time graphs.

Response Headers

Rate-limited responses include headers:

HeaderDescription
Retry-AfterSeconds until limit resets
X-RateLimit-LimitMax requests in window
X-RateLimit-RemainingRequests remaining
X-RateLimit-ResetUnix timestamp of reset