How to Ban/Suspend Users in Laravel Project

Laravel Auth system has a lot of features, but it doesn’t include suspending users for some time, like banning some angry forum user for 14 days to calm down. Luckily, it’s easy to implement, with Middleware. This article will show you how.

Here’s what the banned user will see after they try to log in:

Step 1. New column: users.banned_until

Let’s not just ban user with true/false field like is_banned, I would advise to have timestamp field – if it’s null, then user is not banned, otherwise we know the date, until when.

As an example, we take fresh Laravel 5.7 project with default migrations and make:auth command. Next, we add this column:

php artisan make:migration add_banned_until_to_users_table

Migration file:

class AddBannedUntilToUsersTable extends Migration
    public function up()
        Schema::table('users', function (Blueprint $table) {

All already existing users will have field as NULL, so no one will be banned automatically after this migration, it’s safe.

We also need to add that field to $fillable array in app/User.php model. For convenience, let’s put it into $dates array, too – we will do some Carbon manipulations later.

class User extends Authenticatable
    protected $fillable = [
        'name', 'email', 'password', 'banned_until'

    protected $dates = [

For this article, I will skip the User administration part where administrator would ban/unban user – you can generate such user management system with our generator

In this article, we will assume that some admin somewhere puts the value on users.banned_until as timestamp or NULL. Maybe even directly in the database via Sequel Pro or phpMyAdmin.

Step 2. Middleware CheckBanned

We will create a middleware to check if the user is banned. In that case, we log them out and redirect back to login form with an error message.

php artisan make:middleware CheckBanned

Here’s the file app/Http/Middleware/CheckBanned.php:

class CheckBanned
    public function handle($request, Closure $next)
        if (auth()->check() && auth()->user()->banned_until && now()->lessThan(auth()->user()->banned_until)) {
            $banned_days = now()->diffInDays(auth()->user()->banned_until);

            if ($banned_days > 14) {
                $message = 'Your account has been suspended. Please contact administrator.';
            } else {
                $message = 'Your account has been suspended for '.$banned_days.' '.str_plural('day', $banned_days).'. Please contact administrator.';

            return redirect()->route('login')->withMessage($message);

        return $next($request);

A few things to notice here:

  • We use some Carbon methods like lessThan() or diffInDays() to perform date operations. That’s why earlier we needed to add banned_until field as $dates property in User model.
  • If user is banned for 14 days or less, we show how many days of suspension are left. Otherwise we assume that the account is banned forever.
  • Not sure if you know about str_plural() method to show singular or plural form of the noun, depending on a number. Here’s my old article about it.

Step 3. Using Middleware and Show Error Message

Next, we need to register this middleware to run on every request, so we add its class to app/Http/Kernel.php file group called web:

protected $middlewareGroups = [
    'web' => [

        // ... other middleware classes


Finally, let’s add the message in resources/views/auth/login.blade.php:


<div class="card-body">

    @if (session('message'))
        <div class="alert alert-danger">{{ session('message') }}</div>

    <form method="POST" action="{{ route('login') }}">


Here’s the visual result:

Like our articles?
Check out our Laravel online courses!


  1. Good article, thank you for sharing! One question: Why do you need the middleware for every request? Doesn’t it make more sense to add it in the login controller rather than in a middleware, as it only needs to be checked at the the time of a login?

    • Hi Nico,
      It’s because banning action from admin may happen at any time, even during the time the user is browsing the site, being already logged in. Or they may choose “Remember me” and never have to log in at all.

    • Yes, I’ve tried it actually, before writing the article. But decided to still write the article, so people would know the internals how it can work in a simple way, without any package.

  2. Very good post, as usual!
    I do believe there is a typo though. There should be Carbon::now().
    Also Laravel is deprecating string and array functions. It might be a better idea to use Str::plural() instead of str_plural().

    • Yeah, agree with Str:: comment, Laravel 5.8 came out today with str changes. But working with strings is not the goal of this article, so I think I won’t change the code.
      Carbon::now() thing should not be the reason why it fails, commented above.

  3. Hi , thanks for the awesome tutorial.

    I wanted to find out if I can use the same login if I want to check of the user is suspended using a status column with these value [ 0 – Inactive , 1 – Active , 2 – Suspended ].

    So if I want to check if the user is active and give them access to the system and if they are not active block them and display the appropriate message.

  4. Almost works for me. I’m experiencing a redirection loop, in the middleware controller. Running 5.8. Seems like the redirection to “login” when the ban condition is met is thrashing. Must be something wrong I am doing but how do you keep the redirect to “login” from becoming endlessly recursive?


Please enter your comment!
Please enter your name here