Web API  

API Rate Limiting in ASP.NET Core: Protecting Your Applications from Abuse

Public APIs are constantly exposed to automated bots, accidental traffic spikes, and abusive clients. Without proper safeguards, a single client can overwhelm your application, consume server resources, and degrade performance for every other user.

ASP.NET Core includes built-in rate limiting middleware that makes it easy to control how many requests a client can send within a given time period. By applying appropriate rate limiting policies, you can improve application stability, prevent denial-of-service scenarios, and ensure fair resource usage.

Rather than implementing custom throttling logic, this article explains how to use the built-in ASP.NET Core rate limiting middleware, choose the right algorithm, and configure production-ready policies.

Note: Rate limiting is not a replacement for authentication, authorization, or a Web Application Firewall (WAF). It complements these security measures by controlling request frequency.

Why API Rate Limiting Matters

Without rate limiting, APIs are vulnerable to:

  • Accidental traffic spikes

  • Brute-force login attempts

  • API abuse

  • Credential stuffing attacks

  • Excessive resource consumption

  • Increased infrastructure costs

  • Reduced application availability

Limiting request rates helps maintain consistent performance even during periods of unusually high traffic.

Common Rate Limiting Scenarios

Rate limiting can be applied to:

  • Login endpoints

  • Public APIs

  • File upload endpoints

  • Search APIs

  • Payment APIs

  • Password reset endpoints

  • Third-party integrations

  • AI-powered endpoints

Different endpoints often require different request limits depending on their workload and business requirements.

Rate Limiting Algorithms

ASP.NET Core supports multiple rate limiting strategies.

AlgorithmBest For
Fixed WindowSimple APIs with predictable traffic
Sliding WindowSmoother request distribution
Token BucketAPIs with occasional traffic bursts
Concurrency LimiterLimiting simultaneous requests

Each algorithm provides different trade-offs between fairness, burst handling, and implementation complexity.

Installing the Rate Limiting Middleware

The rate limiting middleware is included with modern versions of ASP.NET Core.

Register the middleware during application startup.

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter(
        "default",
        policy =>
        {
            policy.PermitLimit = 100;
            policy.Window = TimeSpan.FromMinutes(1);
            policy.QueueLimit = 0;
        });
});

This configuration allows up to 100 requests per minute before additional requests are rejected.

Enabling Rate Limiting

Enable the middleware within the request pipeline.

var app = builder.Build();

app.UseRateLimiter();

app.MapControllers();

app.Run();

Without calling UseRateLimiter(), configured policies won't be enforced.

Applying Rate Limiting to Endpoints

Policies can be applied to individual endpoints.

app.MapGet("/weather", () =>
{
    return Results.Ok();
})
.RequireRateLimiting("default");

This approach allows different APIs to use different request limits.

Using a Sliding Window Policy

Sliding window limiting distributes requests more evenly.

builder.Services.AddRateLimiter(options =>
{
    options.AddSlidingWindowLimiter(
        "sliding",
        policy =>
        {
            policy.PermitLimit = 60;
            policy.Window = TimeSpan.FromMinutes(1);
            policy.SegmentsPerWindow = 6;
        });
});

Unlike a fixed window, the sliding window gradually expires requests instead of resetting all limits simultaneously.

Limiting Concurrent Requests

Some operations are expensive rather than frequent.

Use a concurrency limiter for these scenarios.

builder.Services.AddRateLimiter(options =>
{
    options.AddConcurrencyLimiter(
        "uploads",
        policy =>
        {
            policy.PermitLimit = 5;
            policy.QueueLimit = 10;
        });
});

This configuration ensures that only five upload requests execute simultaneously.

Rate Limiting Request Flow

flowchart LR

A[Client Request]
B[Rate Limiter]
C{Limit Exceeded?}
D[Process Request]
E[Return HTTP 429]

A --> B
B --> C
C -->|No| D
C -->|Yes| E

When a client exceeds the configured policy, the middleware immediately returns an HTTP 429 (Too Many Requests) response.

Choosing Appropriate Limits

The ideal request limit depends on the endpoint.

EndpointExample Limit
Login API5 requests/minute
Search API30 requests/minute
Public API100 requests/minute
File Upload10 requests/minute
Payment API20 requests/minute

These values are examples. Monitor production traffic before finalizing rate limits.

Handling Rejected Requests

Customize responses for rejected requests.

builder.Services.AddRateLimiter(options =>
{
    options.OnRejected = async (context, _) =>
    {
        context.HttpContext.Response.StatusCode = 429;

        await context.HttpContext.Response.WriteAsync(
            "Rate limit exceeded.");
    };
});

Providing a clear error response helps clients understand why their requests were rejected.

Common Production Mistakes

ProblemRoot Cause
Legitimate users blockedLimits configured too aggressively
No protection against abuseRate limiting disabled
High server loadLimits set too high
Shared users affectedUsing IP-only identification behind proxies
Unexpected request failuresPolicies applied to incorrect endpoints
Poor client experienceMissing Retry-After information

Most rate limiting issues result from poorly chosen thresholds rather than the middleware itself.

Best Practices

  • Apply different limits to different endpoints.

  • Use stricter limits for authentication APIs.

  • Monitor HTTP 429 responses.

  • Test policies using realistic production traffic.

  • Combine rate limiting with authentication and authorization.

  • Return meaningful error responses for rejected requests.

  • Review limits regularly as traffic patterns evolve.

Common Anti-Patterns

Avoid these common mistakes:

  • Applying identical limits to every endpoint.

  • Disabling rate limiting in production.

  • Using extremely restrictive limits without testing.

  • Ignoring reverse proxy configuration.

  • Assuming rate limiting prevents every denial-of-service attack.

  • Treating rate limiting as a replacement for security controls.

FAQ

Which rate limiting algorithm should I choose?

Fixed Window is suitable for many APIs. Sliding Window provides smoother traffic control, Token Bucket handles bursts effectively, and Concurrency Limiter is ideal for resource-intensive operations.

What HTTP status code is returned when the limit is exceeded?

The middleware returns HTTP 429 (Too Many Requests), indicating that the client has exceeded the configured request limit.

Can different endpoints use different limits?

Yes. ASP.NET Core supports multiple named policies, allowing each endpoint or route group to enforce its own request limits.

Does rate limiting work with reverse proxies?

Yes, but ensure client IP addresses are forwarded correctly using forwarded headers. Otherwise, multiple users may appear to originate from the same IP address.

Conclusion

Rate limiting is a fundamental part of building secure and reliable APIs. By controlling request frequency, you can protect your ASP.NET Core applications from abuse, reduce unnecessary resource consumption, and maintain a consistent experience for legitimate users.

The built-in ASP.NET Core rate limiting middleware provides flexible algorithms, endpoint-specific policies, and straightforward configuration without requiring third-party libraries. When combined with authentication, monitoring, and proper infrastructure design, it helps create resilient APIs that remain responsive even under heavy traffic.