Skip to content
bitzorcas
EN

Concept

Rate limiting

Partitioned rate limiting — three ASP.NET Core rate-limiting policies (Token Bucket, Sliding Window, Fixed Window) with per-tenant and per-caller partitioning.

Last updated

BitzOrcas uses ASP.NET Core’s built-in rate limiting with tenant + caller partitioned policies. Each tenant/caller pair gets its own counter bucket, preventing application callers from sharing anonymous buckets.

Three policies

PolicyAlgorithmWindowUse case
userPolicyToken Bucket1 minuteGeneral REST API endpoints
sensitivePolicySliding Window1 minuteLogin, OTP, password reset
fixedPolicyFixed Window1 minuteInternal/low-frequency services

Partition key format

{tenant_id}:{user_id|client_id}

This ensures application callers (which have client_id but no user_id) are partitioned correctly instead of all falling into an “anonymous” bucket.

Policy parameters

userPolicy (Token Bucket)

new TokenBucketRateLimiterOptions
{
TokenLimit = 2,
TokensPerPeriod = 2,
ReplenishmentPeriod = TimeSpan.FromMinutes(1),
QueueLimit = 0,
AutoReplenishment = true,
}

Allows 2 requests per minute with no queuing.

sensitivePolicy (Sliding Window)

new SlidingWindowRateLimiterOptions
{
Window = TimeSpan.FromMinutes(1),
SegmentsPerWindow = 4,
PermitLimit = 5,
QueueLimit = 0,
}

5 requests per minute — sliding window prevents boundary-burst attacks.

fixedPolicy (Fixed Window)

new FixedWindowRateLimiterOptions
{
Window = TimeSpan.FromMinutes(1),
PermitLimit = 10,
AutoReplenishment = true,
}

10 requests per minute — simple and predictable for internal services.

429 response

All rate-limited requests return RFC 9457 ProblemDetails:

{
"type": "https://docs.bitzsoft.com/problems/rate-limit-exceeded",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit exceeded.",
"errorCode": "RateLimit.Exceeded",
"retryAfter": 60
}

HTTP headers included:

  • Retry-After: 60
  • X-RateLimit-Remaining: 0 (when available)

Usage in endpoints

app.MapPost("/api/notes", async (...) => ...)
.RequireRateLimiting("userPolicy");
app.MapPost("/api/auth/login", async (...) => ...)
.RequireRateLimiting("sensitivePolicy");

Middleware order

Rate limiter middleware is placed after authorization in the pipeline:

ExceptionHandler → CorrelationId → Auth → DelegationToken
→ TenantResolution → Audit → Authorization → RateLimiter → Endpoints

Production considerations

For multi-instance deployments, consider:

  • Redis DistributedRateLimiter — shared counter across instances
  • Gateway-level limiting — YARP/Envoy/Nginx before reaching the API
  • Per-tenant rate plans — configurable limits from billing subscription