Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Johna's avatar

Johna wrote a reply+100 XP

5mos ago

Nevermind, im having the issue again!

After more research I found out :

Laravel’s global throttle logic does not run inside your controller middleware stack.Even if you add your throttle middleware after auth in your route, the rate limiter callback can still execute before the request is guaranteed to have an authenticated user bound to it.

Is this true? Is this by design, some sort of limitation or am I doing something wrong?

I found a workaround by making a custom throttle middleware:

public function handle(Request $request, Closure $next, int $attempts, int $minutes): Response
    {
        $key =  $request->user()->id;

        // Check attemps
        if (RateLimiter::tooManyAttempts($key, $attempts)) {
            return response()->json(
                ['message' => 'Too many requests'],
                Response::HTTP_TOO_MANY_REQUESTS,
                ['Retry-After' => RateLimiter::availableIn($key)]
            );
        }

        // Add hit
        RateLimiter::hit($key, $minutes * 60);
        return $next($request);
    }
Johna's avatar

Johna wrote a reply+100 XP

5mos ago

I don't remember caching the routes. Also after clearing the routes I got other errors. I tried some GET endpoints, cleared routes again now it works.

Johna's avatar

Johna wrote a reply+100 XP

5mos ago

"You cannot rely on having an authenticated user at that point in the lifecycle"

I don't understand, since I'm doing ->middleware(['auth', 'throttle:some-task']);, shouldn't auth middleware run first?

if i do ->by($request->user()?->id ?: $request->ip()), does that mean it will always use the ip for a key?

Johna's avatar

Johna started a new conversation+100 XP

5mos ago

I have this rate limiter

RateLimiter::for('some-task', function ($request) {
	return Limit::perHour(10)->by($request->user()->id);
 });

I want to use it after a user is authenticated

Route::post('todo', [TaskController::class, 'task'])
            ->middleware(['auth', 'throttle:some-task']);

However, I get an error

attempt to read property id on null

I'm sure it's from the rate limiter since if I do

RateLimiter::for('some-task', function ($request) {
	//dd('test');
	return Limit::perHour(10)->by($request->user()->id);
	//dd('limiter passed');
 });

If I uncomment 'test' i get 'test'. However, if i uncomment 'limiter passed', I get the 'id' error

Does the throttle middleware run globally?

How do I throttle by user id?