Rate Limiting in Laravel

What is Rate Limiting in Laravel?

Rate Limiting is a powerful feature in Laravel that limits the number of times users or clients can do specific activities within a given time range. This functionality is frequently used to prevent misuse, safeguard resources, and ensure fair usage of APIs and other endpoints. Laravel's rate limiter is based on a caching mechanism and can be readily adjusted to meet a variety of application requirements.


Cache Configuration

The rate limiter makes use of your application's default cache driver, as specified in the CACHE_STORE environment variable. Setting the limiter key in your cache configuration allows you to specify a different cache driver to use for rate limiting.

'default' => env('CACHE_STORE', 'database'),

'limiter' => 'redis',

How It Works.

Laravel has a RateLimiter facade for communicating with the rate limiter. The most typical approach is attempt, which limits a callback to a certain number of attempts over a set time period.

Basic Example: Limiting Attempts

use Illuminate\Support\Facades\RateLimiter;

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perMinute = 5,
    function () {
        // Action to perform
    }
);

if (! $executed) {
    return 'Too many messages sent!';
}

In this case, the action is limited to five attempts per minute. If the limit is exceeded, the callback is terminated and a custom message is returned.

Custom Decay Rates

You can set a custom decay rate (in seconds) for the rate limit:

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perTwoMinutes = 5,
    function () {
        // Action to perform
    },
    $decayRate = 120
);

The limit allows for five attempts every two minutes.


Manual interaction with the rate limiter.

Laravel offers additional techniques for further control over rate limiting:

Increasing Attempts

You can manually increase the try count on a specific key.

use Illuminate\Support\Facades\RateLimiter;

RateLimiter::increment('send-message:'.$user->id);

// Perform the action

Checking Remaining Attempts

To determine how many attempts remain for a particular key:

if (RateLimiter::remaining('send-message:'.$user->id, 5)) {
    RateLimiter::increment('send-message:'.$user->id);
    // Perform the action
}

Determining Reset Times

To find out how long till new attempts are available:

if (RateLimiter::tooManyAttempts('send-message:'.$user->id, 5)) {
    $seconds = RateLimiter::availableIn('send-message:'.$user->id);
    return 'You may try again in '.$seconds.' seconds.';
}

Clearing Attempts

The clear technique can be used to reset a key's attempt count.

RateLimiter::clear('send-message:'.$user->id);

Rate Limiting Routes

Rate restriction is a typical feature of middleware-based routing. Laravel's ThrottleRequests middleware makes it simple to establish restrictions on HTTP requests.

Basic Route-Level Throttling

Route::middleware('throttle:60,1')->group(function () {
    Route::get('/api/posts', [PostController::class, 'index']);
});

This sets a restriction of 60 requests per minute for the grouped routes.

Define a Custom Limiter

To define a dynamic rate limiter in App\Providers\RouteServiceProvider:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('custom', function (Request $request) {
    return Limit::perMinute(100)->by($request->user()?->id ?: $request->ip());
});

Then, apply it to routes with:

Route::middleware('throttle:custom')->group(function () {
    Route::get('/api/posts', [PostController::class, 'index']);
});

Why is Rate Limiting Important?

  1. Prevents Abuse: Protects your app from excessive requests and malicious attacks.
  2. Ensures Resource Availability: Protects server resources from being overloaded by high-traffic users.
  3. Enhances User Experience: Balancing server load ensures optimal performance.

Best Practices.

  1. Establish Limits: Use route-specific or user-based limits for better control.
  2. Combine with Authentication: Rate-limit users based on roles, tokens, or session identifiers for more secure applications.
  3. Optimize Cache Usage: Use high-performance cache drivers, such as Redis, for high-traffic applications.
  4. Monitor Rate-Limited Routes: Use Laravel Telescope or logging tools to track throttled requests and discover bottlenecks.
  5. Minimize Global Overheads: Use rate limiting sparingly and target only endpoints prone to abuse or heavy usage.

Summary.

Rate Limiting in Laravel gives developers a powerful, customizable tool for controlling request frequency and protecting their applications. Caching, middleware, and dynamic limiters can be used to efficiently manage resource utilization while keeping a consistent user experience. With correct implementation, Laravel's rate-limiting features may help protect and optimize applications of any size.

Read more