What is Role-Based Authentication in Laravel 11?
Role-Based Authentication (RBAC) in Laravel 11 lets you control access and features after login based on a user's role (admin, editor, user, etc.).
Using a single authentication guard, you store a role value in the users table and enforce rules via:
- Custom middleware — Quick route protection (e.g.,
'role:admin') - Gates — Simple closure-based checks
- Policies — Model-specific authorization logic
This lightweight method suits most apps needing tiered access without separate logins. For advanced needs, add Spatie Laravel-Permission. Unlike multi-guard auth (separate logins/tables), RBAC keeps everything unified and simple.

Table Of Content
1 Prerequisites
- PHP ≥ 8.2
- Composer
- MySQL / preferred DB
2 Introduction
In Laravel 11, implementing role-based authentication is a lightweight and efficient way to control access for different user types—such as User, Editor, and Admin—without the complexity of multiple authentication guards. This approach uses a single web guard combined with a custom middleware that checks a role column in your users table, ensuring secure and role-specific route protection.
Whether you're building a simple CMS, admin panel, or multi-user application, this method provides quick role restrictions while maintaining Laravel's elegant authentication system. For more advanced needs (like granular permissions), you can later integrate packages such as Spatie Laravel-Permission.
In this step-by-step guide, you'll learn how to set up role-based access control in Laravel 11 using custom middleware, including database migration, middleware creation, alias registration in bootstrap/app.php, route protection, and practical testing tips. Perfect for developers seeking a modern, secure solution in 2026.
3 Create a Fresh Laravel 11 Project
3.1 Install Laravel Project For Laravel 11 Custom Middleware
Use the following command to install new Laravel Project.
composer create-project laravel/laravel laravel-role-auth
Then, navigate to your project directory:
cd laravel-role-auth
3.2 Configure MySql Database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel11
DB_USERNAME=root
DB_PASSWORD=
4 Install Breeze (Blade + auth scaffolding)
Note: laravel/ui is deprecated; for modern Laravel 11, use Breeze:
composer require laravel/breeze --dev
php artisan breeze:install blade
npm install && npm run dev # or npm run build
php artisan migrate
5 Update User Model and User Migration
Update Migration File
Now we have to modify migration file Open the file /database/migrations/xxxx_xx_xx_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->tinyInteger('role')->default(0);
$table->rememberToken();
$table->timestamps();
});
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
Schema::dropIfExists('password_reset_tokens');
Schema::dropIfExists('sessions');
}
};
?>
Now we need to run command below to create table in database
php artisan migrate
Modify User Model File
Open the file /app/Models/User.php
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
'role',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
// Optional helper method
public function isAdmin(): bool
{
return $this->role === 'admin';
}
public function isEditor(): bool
{
return $this->role === 'editor';
}
}
?>
6 Create custom Role middleware
php artisan make:middleware Role
The command will generate a file under directory /app/Http/Middleware/Role.php
Implement Logic in Middleware
We have to add new parameter '$role' to validate User role requested from web.php, we will implement if the role is match will allow to the next request, otherwise will redirect to home page open the file /app/Http/Middleware/Role.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class Role
{
public function handle(Request $request, Closure $next, string $role): Response
{
if (!Auth::check()) {
return redirect()->route('login');
}
if (Auth::user()->role !== $role) {
return redirect()->route('dashboard')
->with('error', 'You do not have permission to access this page.');
}
return $next($request);
}
}
?>
7 Register the Middleware - bootstrap/app.php
Laravel 11 introduces significant changes to middleware handling. In previous versions, you could register middleware in the Kernel.php file. However, with Laravel 11, you must define middleware in the bootstrap/app.php file.
Open the file bootstrap/app.php Add inside ->withMiddleware(...):
<?php
namespace App\Http\Controllers\Auth;
uuse Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
$middleware->alias([
'role' => \App\Http\Middleware\Role::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
?>
8 Modify Controller - HomeController and LoginController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function index()
{
return redirect()->route('dashboard');
}
}
?>
9 Define a Route
routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\HomeController; // We'll create this
Route::get('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
$msg = match (auth()->user()->role) {
'admin' => 'Welcome, Administrator! You have full access.',
'editor' => 'Hello Editor! You can edit content.',
'user' => 'Hi User! Enjoy browsing.',
default => 'Welcome!',
};
return view('dashboard', compact('msg'));
})->middleware(['auth', 'verified'])->name('dashboard');
// Role-specific dashboards (optional - or keep everything in /dashboard)
Route::middleware(['auth', 'role:editor'])->group(function () {
Route::get('/editor', fn() => view('dashboard', ['msg' => 'Editor Area']))->name('editor');
});
Route::middleware(['auth', 'role:admin'])->group(function () {
Route::get('/admin', fn() => view('dashboard', ['msg' => 'Admin Panel']))->name('admin');
});
require __DIR__.'/auth.php';
10 Update Home Blade File
resources/views/dashboard.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Dashboard
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
{{ $msg ?? 'Welcome to your dashboard!' }}
<p class="mt-4">
Your role: <strong>{{ auth()->user()->role }}</strong>
</p>
@if (session('error'))
<div class="mt-4 p-4 bg-red-100 text-red-700 rounded">
{{ session('error') }}
</div>
@endif
</div>
</div>
</div>
</div>
</x-app-layout>
11 Add Seeder for Testing
Use the following artisan command to Create Controller.
php artisan make:seeder UserRoleSeeder
database/seeders/UserRoleSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class UserRoleSeeder extends Seeder
{
public function run(): void
{
User::create([
'name' => 'Regular User',
'email' => 'user@example.com',
'password' => Hash::make('password'),
'role' => 'user',
]);
User::create([
'name' => 'Content Editor',
'email' => 'editor@example.com',
'password' => Hash::make('password'),
'role' => 'editor',
]);
User::create([
'name' => 'Administrator',
'email' => 'admin@example.com',
'password' => Hash::make('password'),
'role' => 'admin',
]);
}
}
?>
Use the following artisan command to run seeder.
php artisan db:seed --class=UserRoleSeeder
12 Folder Structure
13 Run Laravel Server to Test the App
php artisan serve
Testing
- Go to /register or /login → create/login with any account (or use seeder ones)
- After login → /dashboard shows role message
- Try /admin → only admin can access, others get redirected with error
- Same for /editor
14 Conclusion
Written by Revathi M
PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel
Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.
Frequently Asked Questions
No, it uses the default single 'web' guard with role checks in middleware. Separate guards (e.g., admin) are not implemented.
In the controller (e.g., HomeController), create methods like userHome() or adminHome() and return role-specific views or messages.
Create a seeder to insert users with different role values (0,1,2), then login as each to test protected routes.
Common issues: Incorrect role value in database, middleware not registered properly in bootstrap/app.php, or missing 'auth' middleware before role check.
The tutorial implements role-based authentication using a single 'web' guard. Roles (user, manager, admin) are stored in a 'role' column on the users table and checked via custom middleware.
You need PHP 8.2+, Composer, MySQL database configured in .env, and Laravel UI for authentication scaffolding (composer require laravel/ui).
Update the users migration to add $table->tinyInteger('role')->default(0); then run php artisan migrate. Roles: 0=user, 1=manager, 2=admin (cast to strings in User model).
Run php artisan make:middleware UserRoleMiddleware. In handle(), check if Auth::user()->role matches the passed parameter, else redirect.
In bootstrap/app.php, use ->withMiddleware() to alias 'role' to your UserRoleMiddleware class.
Use middleware('role:user') (or 'role:admin') on route groups after 'auth' middleware to restrict access based on user role.
