API rate limiting

How to take advantage of the built-in rate limiting middleware of ASP.NET Core in Umbraco.

Since ASP.NET Core 7, you can use the built-in rate limiting middleware to rate limit your APIs. You can apply the EnableRateLimiting and DisableRateLimiting attributes to add rate limiting on a controller or endpoint level. In this article, we will go through how you can configure and utilize different rate limiting strategies for Umbraco APIs.

What is rate limiting?

Rate limiting helps control the number of requests to an API, typically within a specified time frame or based on other parameters. This ensures the stability, availability, and security of your APIs. The key benefits are:

  • Preventing server or application overload

  • Improving security and protecting against DDoS attacks

  • Reducing unnecessary resource usage, thereby cutting down on costs

Configuring rate limiting

You can configure rate limiting in Umbraco by composition. To use the middleware, you need to register the rate limiting services first:

ApiRateLimiterComposer.cs
public class ApiRateLimiterComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.Services.AddRateLimiter(rateLimiterOptions =>
        {
            // Default is 503 (Service Unavailable)
            rateLimiterOptions.RejectionStatusCode = StatusCodes.Status429TooManyRequests;

            // Write your code to configure the middleware here (rate limiting policies)
        });
    }
}

After that, you have to apply the RateLimitingMiddleware by creating an Umbraco pipeline filter. UseRateLimiter() must be called after UseRouting(), therefore we use the PostRouting to make sure this happens in the correct order:

With the set-up in place, let's take a look at some limiter options.

Global limiter

Inside AddRateLimiter() we can use the GlobalLimiter option to set a global rate limiter for all requests:

In the above example, we have added a FixedWindowLimiter and configured it to automatically replenish permitted requests and permit 2 requests per 10 seconds. There are different algorithms and techniques for implementing rate limiting, which can vary depending on your use case. For more information, check the currently supported rate limiter algorithms.

Limit specific endpoints

If you want to be more granular, you can configure different rate limits for different endpoints in AddRateLimiter() as well:

In the code snippet above, we have configured 2 fixed window limiters with different settings, and different policy names ("fixed1" and "fixed2"). We can apply these policies to specific endpoints within Umbraco using the same UmbracoPipelineFilter:

This part of the code shows how to apply the fixed1 policy to the AuthenticationController.PostRequestPasswordReset endpoint, responsible for handling password reset requests. We can do that by dynamically modifying the endpoint's metadata - attaching the EnableRateLimitingAttribute with the name of the policy which needs to be applied. This enables us to enforce the defined rate limits on a particular endpoint.

For your reference, here is the complete ApiRateLimiterComposer.cs implementation.

When Umbraco runs behind a WAF or reverse proxy, rate-limiting may fail if the client IP address is not forwarded correctly. Configure your proxy or WAF to send the original client IP using headers like X-Forwarded-For. This will prevent all requests appearing to come from one IP address which would cause incorrect rate-limit enforcement.

Last updated

Was this helpful?