How to Implement Laravel Rate Limit with ThrottleRequests?

Rate limiting is a valuable feature for Laravel websites to maintain performance and enhance security. It controls the number of requests users or clients can make over a set period. That helps prevent brute-force attacks and excessive traffic that could overload the server.

In this blog, we’ll explore how rate limiting works behind the scenes, providing you with a clear understanding of its mechanics. Then, we’ll walk through how Laravel development experts set up and use rate limits on their sites. Additionally, we’ll dive into the best practices that you can follow when implementing rate limits in Laravel.

What is Rate Limiting in Laravel?

Rate limiting in Laravel is a feature that allows you to control the rate at which users can make requests to your application. It helps to prevent brute-force attacks, denial-of-service (DoS) attacks, and other types of malicious activity.

In Laravel, rate limiting is implemented using a middleware called throttle. This middleware checks the number of requests made by a user or IP address within a certain time frame (e.g., 1 minute) and blocks further requests if the limit is exceeded.

Here are some key aspects of rate limiting in Laravel:

  • Request counting: Laravel counts the number of requests made by a user or IP address within a certain time frame.
  • Time frame: The time frame is configurable and can be set to any duration (e.g., 1 minute, 1 hour, etc.).
  • Rate limit: The rate limit is the maximum number of requests allowed within the time frame.
  • Blocking: If the rate limit is exceeded, Laravel blocks further requests from the user or IP address for a specified duration.

These aspects of rate limiting lead to several benefits, such as:

  • Preventing abuse: Rate limiting helps prevent malicious activity, such as brute-force attacks or DoS attacks.
  • Improving security: By limiting the number of requests, it reduces the attack surface improving website security.
  • Reducing server load: Rate limiting can help reduce the load on your server by preventing excessive requests.

Now that we have an overview of the Laravel rate limit let’s begin with how it works for a better understanding.

How does the Laravel Rate Limit Work?

Rate limiting in Laravel works through a combination of middleware, the cache system, and the RateLimiter facade. Here’s a breakdown of the process:

  • Request Interception: When a request comes in, it passes through Laravel’s middleware stack. If rate limiting is applied, the ‘throttle’ middleware intercepts the request.
  • Identification: Laravel identifies the client making the request. This can be done in several ways:
    • By IP address for guest users.
    • By authenticated user ID for logged-in users.
    • By a custom key, you define.
  • Counter Management: Laravel uses its cache system to store and manage rate limit counters. Each counter is associated with a unique key, typically combining the client identifier and the route or group being accessed.
  • Limit Checking: The RateLimiter checks if the request should be allowed based on the configured limits. It does this by:
    • Retrieving the current counter value from the cache.
    • Checking if this value exceeds the defined limit.
    • If not exceeded, increment the counter and allow the request.
    • If exceeded, deny the request.
  • Response Handling: This stage handles the requests. Here is how:
    • If the limit is not exceeded, the request proceeds normally.
    • If the limit is exceeded, Laravel returns a 429 (Too Many Requests) HTTP response by default.
  • Headers: Laravel adds rate limit information to the response headers:
    • X-RateLimit-Limit: The maximum number of requests allowed in the time window
    • X-RateLimit-Remaining: The number of requests remaining in the current window
    • Retry-After: The number of seconds to wait before making another request (only on 429 responses)
  • Decay and Reset: After the specified time, the rate limit counter is automatically reset or decayed, allowing new requests from the client.

Here’s a code example of how rate limiting is typically implemented in Laravel:

Route::middleware('throttle:60,1')->group(function () {
    Route::get('/api/users', function () {
        //
    });
});

In this example, ‘60,1’ means 60 requests per 1 minute. Laravel’s RateLimiter also allows for more complex rate limiting scenarios. For instance, you can create custom rate limiters using the RateLimiter facade:

use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('uploads', function (Request $request) {
    return Limit::perMinute(100)->by($request->ip());
});

This creates a named rate limiter that can be used in route definitions:

Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/audio', function () {
        //
    });
    Route::post('/video', function () {
        //
    });
});

Laravel’s rate limiting system is flexible and can be customized to fit various website needs, from simple API rate limiting to complex control systems. With that, now let’s begin to learn how professional Laravel developers set up rate limits on their website.

Struggling to build a secure Laravel website?

How to Set Up Laravel Rate Limit with ThrottleRequests?

To set up and use rate limiting in Laravel, you can leverage ThrottleRequests middleware,  and custom rate limiters defined in RouteServiceProvider. Here’s a stepwise process you can follow:

Step 1: Install Laravel

Ensure you have a Laravel project installed. If not, first install Laravel using composer command:

composer create-project laravel/laravel laravel-rate-limit

After installation, move into the project directory:

cd laravel-rate-limit

Step 2: Configure Rate Limiting

Laravel’s rate limiting configuration is typically done in the app/Providers/RouteServiceProvider.php file. Open this file and locate the boot method.

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
public function boot()
{
    $this->configureRateLimiting();
    // ...
}
protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
}

This sets up a basic rate limit of 60 requests per minute for routes in the API group. It identifies users by their ID if they’re logged in, or by their IP address if they’re not.

Step 3: Apply Rate Limiting to Routes

Laravel’s default throttle middleware provides a simple way to rate limit routes. It controls how many requests can be made within a specific time frame. Here is how you can apply throttle middleware to a Route:

Route::get('/profile', function () {
    return 'Profile Page';
})->middleware('throttle:60,1');

This allows 60 requests per minute for the /profile route. If a user exceeds the limit, Laravel responds with a 429 Too Many Requests HTTP status code.

Step 4: Apply API Throttling

In routes/api.php, Laravel applies rate limiting with the default API middleware group. You can configure this limit in the config/ratelimiting.php file. Here is and example of route group with throttling:

Route::middleware('throttle:api')->group(function () {
    Route::post('/register', 'UserController@register');
    Route::get('/user', 'UserController@show');
});

By default, Laravel limits 60 requests per minute per user or IP for all API routes.

Step 5: Customize Throttling Rules

You can modify the default rate limits by editing the config/ratelimiting.php file. Here is a code example:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
return [
    'api' => Limit::perMinute(100)->by(fn($request) => $request->ip()),
];

This configuration allows 100 requests per minute per IP for API routes. You can modify the rate limit dynamically based on conditions like user roles or tokens.

Step 6: Dynamic Rate Limiting

For more complex scenarios, you can create dynamic rate limiters. Add this to your RouteServiceProvider:

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->isVip()
                ? Limit::none()
                : Limit::perMinute(10);
});

Then use it in your routes:

Route::middleware('throttle:uploads')->post('/upload', [UploadController::class, 'store']);

This creates a dynamic rate limiter named uploads. It checks if the user is VIP. If so, no limit is applied (Limit::none()). Otherwise, it applies a limit of 10 requests per minute. The route then uses this uploads rate limiter.

Step 7: Customize Rate Limit Responses

To customize the response when a rate limit is exceeded, edit the app/Exceptions/Handler.php file:

use Illuminate\Http\Exceptions\ThrottleRequestsException;
public function register()
{
    $this->renderable(function (ThrottleRequestsException $e, $request) {
        return response()->json([
            'message' => 'Too many requests. Please try again later.',
        ], 429);
    });
}

This code customizes the response when a rate limit is exceeded. It returns a JSON response with a custom message and a 429 (Too Many Requests) status code.

Step 8: Rate Limiting in Controllers

You can also apply rate limiting within your created controllers in Laravel. Here is the code you can use:

use Illuminate\Support\Facades\RateLimiter;
class PostController extends Controller
{
    public function store(Request $request)
    {
        if (RateLimiter::tooManyAttempts('create-post:'.$request->ip(), $perMinute = 1)) {
            return response()->json([
                'message' => 'You can only create 1 post per minute.',
            ], 429);
        }
        RateLimiter::hit('create-post:'.$request->ip());
        // Create the post...
    }
}

In the above code the RateLimiter::tooManyAttempts() checks if the rate limit has been exceeded. The RateLimiter::hit() increments the attempt counter. This approach allows for more control over rate limiting within controller methods.

Step 9: Testing Rate Limits

Create a test in your tests/Feature directory to ensure your rate limits are working:

use Tests\TestCase;
class RateLimitTest extends TestCase
{
    public function test_rate_limiting()
    {
        for ($i = 0; $i < 60; $i++) {
            $response = $this->get('/api/user');
            $response->assertStatus(200);
        }
        $response = $this->get('/api/user');
        $response->assertStatus(429);
    }
}

This test makes 60 requests, which should all succeed. The 61st request should fail with a 429 status, as it exceeds the rate limit.

Step 10: Monitoring Rate Limits

To monitor rate limit hits, you can listen for cache events. Add the below code to your AppServiceProvider:

use Illuminate\Support\Facades\Event;
use Illuminate\Cache\Events\CacheHit;
public function boot()
{
    Event::listen(function (CacheHit $event) {
        if (Str::startsWith($event->key, 'laravel_cache:limiter')) {
            \Log::info('Rate limit hit: ' . $event->key);
        }
    });
}

The above listens for CacheHit events. It checks if the cache key starts with ‘laravel_cache:limiter‘, which indicates a rate limit hit. If the rate limit is exceeded, it logs the information of the client. Additionally, consider integrating external monitoring tools like Sentry or Laravel Telescope to monitor request patterns and identify misuse.

Step 11: Clear Rate Limits

If you need to clear rate limits (e.g., for testing), you can do so using the cache command:

\Cache::flush();

This command clears the entire cache, which includes rate limit counters. It’s useful for testing or resetting rate limits, but should be used cautiously in the production environment.

Remember, rate limiting is an important tool for protecting your site from abuse, but it should be used judiciously. Set limits that protect your website without unnecessarily restricting legitimate users. Now that we know the implementation let’s begin with the best practices that Laravel development services follow when using rate limiting.

Best Practices for Using Laravel Rate Limit

When implementing rate limits in Laravel, following best practices ensures that your website performs optimally and remains secure. Below are the best practices for using rate limits effectively in Laravel:

  • Set reasonable limits: Set limits that are reasonable for your website and users. If the limits are too low, users may become frustrated and leave your site.
  • Use global and route-specific limits: Global limits can help prevent overall abuse, while route-specific limits can help prevent abuse on specific routes.
  • Use dynamic rate limiting: Dynamic rate limiting allows you to adjust the rate limit based on the user’s behavior. For example, you can increase the rate limit for users who have a good reputation or decrease it for users who have a history of abuse.
  • Implement a retry mechanism: Implement a retry mechanism that allows users to retry a request after a certain amount of time. This can help prevent users from becoming frustrated and leaving your website.
  • Use IP-based rate limiting: For unauthenticated users, it’s a good idea to use IP-based rate limiting to prevent abuse from a single IP address. This can help mitigate the risk of a single user or bot making excessive requests.
  • Consider using a distributed cache: If your application is running on multiple servers, use a distributed cache like Redis or Memcached to store the rate limit counters. That will ensure the rate limits are consistently applied across all servers.
  • Regularly review and adjust your rate limits: Monitor your website’s usage patterns and adjust your rate limits accordingly. Limits that were appropriate when your application was smaller may need to be increased as your user base grows.
  • Consider using a rate limiting service: If you don’t want to manage the complexity of rate limiting, consider using a third-party rate limiting service like Cloudflare or Datadog.

By following these best practices, you can protect your Laravel site from abuse while maintaining a smooth user experience. If you want to build a site that ensures security and performs optimally, consider hiring Laravel developers.

Need expert assistance with your Laravel project?

FAQs About Using Laravel Rate Limit

What is the rate limit for Laravel 11 routes?
In Laravel 11, the default rate limit for routes is typically set to 60 requests per minute per user. It is applied using the ThrottleRequests middleware. However, you can customize this limit as per your website requirements by defining it in your route definitions through the RateLimiter class.
How do I turn off the rate limit in Laravel?
To disable rate limiting for specific routes in Laravel, you can simply remove the throttle middleware from the route definition. Alternatively, if you want to disable rate limiting globally, you can remove the middleware from the app/Http/Kernel.php file. By doing so, all routes will be removed from rate limiting.
Can I dynamically adjust rate limits based on server load?
While Laravel does not provide this functionality, you can implement custom logic to adjust rate limits dynamically based on server performance. For example, you can monitor server metrics and change limits based on current load conditions.

Wrapping Up

Implementing rate limits in Laravel ensures your site remains secure and efficient by controlling how often users can make requests. Understanding how rate limiting works can make its implementation easy.

With the use of middleware like throttle, you can add rate limit functionality to your site. Further, you can customize the rate limit or use dynamic rate limiting to ensure security while maintaining user experience.

If you are looking to build a site that performs well and is secured, hire Laravel developers.

author
Mayur Upadhyay is a tech professional with expertise in Shopify, WordPress, Drupal, Frameworks, jQuery, and more. With a proven track record in web development and eCommerce development.

Leave a comment