Limit Repeated Actions with Laravel RateLimiter::attempt()
Not every rate limit needs to apply to an entire API route.
Sometimes you want to limit a specific action, such as sending verification emails or requesting an OTP, without restricting other operations.
Laravel provides RateLimiter::attempt() for this purpose.
Basic Usage
use Illuminate\Support\Facades\RateLimiter;
$executed = RateLimiter::attempt(
'send-otp:' . $user->id,
3,
function () use ($user) {
// Send the OTP...
},
60
);
if (! $executed) {
return response()->json([
'message' => 'Too many requests. Please try again later.',
], 429);
}
Here:
- The key identifies the action for this user.
3allows up to three attempts.- The callback contains the operation to execute.
60sets the decay period in seconds.
If the limit has been reached, Laravel returns false without executing the callback. Otherwise, it returns the callback's result or true.
Real-World Example
Imagine a system that allows users to request password-reset emails.
$sent = RateLimiter::attempt(
'password-reset:' . $user->id,
3,
function () use ($user) {
Mail::to($user->email)
->send(new PasswordResetNotice($user));
return true;
},
300
);
if (! $sent) {
return response()->json([
'message' => 'Please wait before requesting another email.',
], 429);
}
This limits the operation to three attempts per five-minute decay period for each user.
When Should You Use It?
- OTP generation
- Password-reset emails
- Verification messages
- Expensive user-triggered operations
- Repeated actions that need individual limits