Ever built a dashboard page that should only be accessible to admins, but it turns out anyone who knows the URL can get in? This is where middleware comes in. Middleware is a "filter layer" that inspects every request before it reaches the controller. In this article you'll learn how middleware works in Laravel and build your own middleware to check a user's role — complete with code.
What Is Middleware?
The analogy is like a security guard at a building's entrance. Before a guest enters the room (the controller), the guard (the middleware) checks first: do they have an access card? Are they logged in? Do they have permission? If they pass, the guest is allowed in. If not, they are directed out (redirect) or rejected.
Every request in Laravel passes through a chain of middleware before reaching the main logic. Examples of Laravel's built-in middleware: auth (ensures the user is logged in) and throttle (limits the number of requests).
How to Create Middleware
Use the following Artisan command:
php artisan make:middleware CheckRole
This command creates the file app/Http/Middleware/CheckRole.php. The handle() method is where the checking logic goes:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckRole
{
public function handle(Request $request, Closure $next, string $role)
{
// Check whether the user is logged in and has the right role
if (! $request->user() || $request->user()->role !== $role) {
abort(403, 'You do not have access to this page.');
}
// Passed the check, continue the request to its destination
return $next($request);
}
}
Note the third parameter $role — this lets us pass a dynamic value from the route (for example "admin" or "editor").
Registering the Middleware
To call it by a short name, register its alias. In Laravel 11, open bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role' => \App\Http\Middleware\CheckRole::class,
]);
})
In Laravel 10 and below, the alias is registered in the $routeMiddleware array in app/Http/Kernel.php.
Applying Middleware to a Route
Now protect a route by passing the role parameter:
// Only admins may enter
Route::get('/dashboard', [DashboardController::class, 'index'])
->middleware('role:admin');
// Multiple routes at once
Route::middleware('role:admin')->group(function () {
Route::get('/users', [UserController::class, 'index']);
Route::get('/settings', [SettingController::class, 'index']);
});
The colon (role:admin) is how you pass a parameter to the middleware. The value admin goes into the $role variable from earlier.
"Before" vs "After" Middleware
Middleware can run before or after the request is processed:
- Before — the logic runs before
return $next($request). Good for access checks (like the example above). - After — the logic runs afterward, using the resulting response. Good for logging or adding headers.
public function handle(Request $request, Closure $next)
{
$response = $next($request); // process first
$response->header('X-App', 'MyApp'); // then modify the response
return $response;
}
Frequently Asked Questions (FAQ)
What's the difference between global middleware and route middleware?
Global middleware runs on every request (for example CORS handling), while route middleware only runs on specific routes that you define.
Can a single route have multiple middleware?
Yes. Use an array: ->middleware(['auth', 'role:admin']). Middleware runs in the order it is written.
Why isn't my middleware working?
Check three things: the alias is registered, the alias name in the route is correct, and run php artisan optimize:clear because routes are often cached.
Conclusion
Middleware is Laravel's way of filtering requests before they reach the controller — ideal for authentication, role checking, logging, and access restriction. With a single CheckRole middleware, you can secure an entire admin area neatly without repeating the check code in every controller.
Next, learn How to Build Login and Register in Laravel with Breeze to complete your authentication system, and How to Fix the "Route [login] not defined" Error, which often appears when using the auth middleware.