Laravel cookbook · Beginner
Rate limit routes per user and per IP
Login and public APIs are abused by scripts, and one heavy user slows everyone down.
Approach
Define named limiters that key by user ID when authenticated and by IP otherwise, with stricter limits for login
(keyed by email and IP), and apply them with the throttle middleware.
Solution
<?php
// app/Providers/AppServiceProvider.php (boot)
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('api', function (Request $request) {
return $request->user()
? Limit::perMinute(600)->by('user:'.$request->user()->id)
: Limit::perMinute(60)->by('ip:'.$request->ip());
});
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(5)->by(strtolower((string) $request->input('email')).'|'.$request->ip()),
Limit::perMinute(30)->by('ip:'.$request->ip()),
];
});
<?php
// routes/web.php
use App\Http\Controllers\Auth\LoginController;
use Illuminate\Support\Facades\Route;
Route::post('/login', [LoginController::class, 'store'])->middleware('throttle:login');
Pitfalls
- Running behind a load balancer without trusted proxies configured, so every request has the same IP.
- Limits stored in the
arrayorfilecache with several servers. - Returning different errors for "unknown email" and "wrong password", which helps attackers.
Variations
- Customise the 429 response with
->response(fn () => ...)on the limit. - Apply coarse limits at the CDN or gateway as well.
Further reading: Rate limiting
Reference: https://laravel.com/docs/13.x/routing#rate-limiting
More Laravel recipes
- Authorize actions with policies
- Cache expensive data with stale-while-revalidate
- Call external APIs with timeouts, retries and fakes
- Catch N+1 queries with strict Eloquent mode
- Delete old records automatically with prunable models
- Dispatch events and listeners after the transaction commits
- Issue scoped API tokens with Sanctum
- Make queued jobs reliable with retries, backoff and uniqueness