Laravel display warning before rate limit lockout

Viewed 41

I have a custom rate limiting rule in my RouteServiceProvider.php which looks like so;

protected function configureRateLimiting()
{
    RateLimiter::for('example', function (Request $request) {
        return Limit::perHour(5)->by(optional($request->user())->id ?: $request->ip())->response(function () {
            return response()->view('auth.login', [
                'error' =>
                    'You have exceeded the maximum number of login attempts. ' .
                    'Your account has been blocked for security reasons.',
                'page' => 'login',
            ], 422);
        });
    });
}

This locks out the user after 5 attempts in an hour.

I would like to add a warning though after 2 attempts aswell, something like you have had two failed login attempts. If you continue entering an incorrect password your account will be locked.

I have tried the following in my login controller, but it doesnt work;

if (RateLimiter::remaining(optional($request->user())->id ?: $request->ip(), 2)) {
    RateLimiter::hit(optional($request->user())->id ?: $request->ip());

    return view('auth.login')->with([
        'error' => 'You have had two failed login attempts. If you continue entering an incorrect password your account will be locked.',
        'page' => 'login'
    ]);
}

Is this possible? I cant find anything regarding this.

Cheers,

1 Answers

the rate limiter information will be pass into the reponse headers X-RateLimit-Limit and X-RateLimit-Remaining which you may or may not be able to extract

It would be much easier to manually interact with RateLimiter class and manually increment the limiter, this way, you can return the remaining attempt and all the other information.

here's a basic example;

add the class use Illuminate\Support\Facades\RateLimiter;

then manually invoke hit and count the remaining attempts,

Route::get('/whatever-login-route', function( Request $request ) {
    
    $key = 'login-limit:'.$request->ip;

    //RateLimiter::resetAttempts( $key ); // resetting attempts
    //RateLimiter::clear( $key ); // resetting attempts and lockout timer

    return [
        'hit' => RateLimiter::hit($key, 3600),
        'remaining' => RateLimiter::remaining($key, 5),
        'reset_at' => RateLimiter::availableIn($key)
    ];

});

This is just a basic example, but as you can see, in your login controller, you can pass the remaining or hit value and do your warning message after 2 hits, and return an error message with 429 header if the remaining value is less than 1 or hit value is more than 5.

Example usage in your case

$key = optional($request->user())->id ?: $request->ip(); 
$hit = RateLimiter::hit($key, 3600 ); // 2nd parameter is the value lockout timer in seconds
$remaining = RateLimiter::remaining($key, 5) // 2nd parameter is the number of allowed attempts in lockout define above

if ( $hit == 2 ) { // if ( $remaining == 3 )

    return view('auth.login')->with([
        'error' => 'You have had two failed login attempts. If you continue entering an incorrect password your account will be locked.',
        'page' => 'login'
    ]);
}
Related