Frontend & Architecture6 min read

API Rate Limiting Strategies for Secure Applications

Md Shahed Alam
Md Shahed Alam
January 15, 2025
API Rate Limiting Strategies for Secure Applications

A few months ago, a client called me because their API was down. Someone had written a script that was making 10,000 requests per minute to their search endpoint. The server was overwhelmed. Legitimate users could not get through.

They had no rate limiting. It took 10 minutes to add it. The problem never happened again.

Rate limiting is one of those things that seems optional until it is not.

What rate limiting does

Rate limiting says: "You can make X requests per Y time period. After that, you get a 429 Too Many Requests response until the window resets."

This protects your server from abuse, prevents one user from hogging resources, and makes brute-force attacks much harder.

Laravel's built-in rate limiting

Laravel has excellent rate limiting built in. You configure it in RouteServiceProvider (or directly in routes):

php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

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

Then apply it to your routes:

php
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::get('/products', [ProductController::class, 'index']);
});

That is it. 60 requests per minute per user. After that, they get a 429 response.

Different limits for different users

Premium users should get higher limits. Free users get lower limits. This is easy to implement:

php
RateLimiter::for('api', function (Request $request) {
    $user = $request->user();
    
    if (!$user) {
        // Unauthenticated requests: 20 per minute by IP
        return Limit::perMinute(20)->by($request->ip());
    }
    
    if ($user->plan === 'premium') {
        return Limit::perMinute(500)->by($user->id);
    }
    
    return Limit::perMinute(60)->by($user->id);
});

Rate limit headers

When you use Laravel's throttle middleware, it automatically adds headers to every response:

text
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
Retry-After: 30  (only on 429 responses)

These headers let API clients know how many requests they have left and when they can try again. Good API clients use these to avoid hitting the limit.

Protecting specific endpoints more aggressively

Some endpoints need stricter limits. Login endpoints are a classic example — you want to prevent brute-force password attacks:

php
RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(5)->by($request->input('email')),
        Limit::perMinute(20)->by($request->ip()),
    ];
});

Route::post('/login', [AuthController::class, 'login'])
    ->middleware('throttle:login');

This limits login attempts to 5 per minute per email address and 20 per minute per IP. An attacker trying to brute-force a password will be stopped very quickly.

Use Redis for high-traffic APIs

By default, rate limiting uses your cache driver. For high-traffic APIs, make sure your cache driver is Redis. It is much faster than the database for this kind of operation.

Rate limiting is a small investment with a big payoff. Add it to every API you build.

APIRate LimitingSecurityLaravel

Ready to build something great?

Let's talk about your project. We will give you honest advice, a clear plan, and a fair price. No pressure, no sales pitch.

Free consultation
No commitment required
Response within 24 hours