Laravel Middleware Guide
Create, register, and apply Laravel middleware: HTTP filters, authentication guards, throttling, terminable middleware, and group configuration.
1. Creating Middleware
// php artisan make:middleware EnsureApiKey
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureApiKey
{
public function handle(Request $request, Closure $next): Response
{
$key = $request->header('X-API-Key') ?? $request->query('api_key');
if (! $key || ! ApiKey::where('key', $key)->where('is_active', true)->exists()) {
return response()->json(['error' => 'Invalid API key'], 403);
}
return $next($request);
}
}
// Middleware with parameters
class RequireRole
{
public function handle(Request $request, Closure $next, string ...$roles): Response
{
if (! $request->user() || ! in_array($request->user()->role, $roles)) {
abort(403, 'Insufficient permissions');
}
return $next($request);
}
}
// Usage: Route::middleware(['auth', 'role:admin,editor'])->group(...);
2. Registering Middleware (Laravel 11+)
// bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
->withMiddleware(function (Middleware $middleware) {
// Global middleware
$middleware->append(LogRequests::class);
$middleware->prepend(TrustProxies::class);
// Alias
$middleware->alias([
'role' => RequireRole::class,
'api.key' => EnsureApiKey::class,
'verified' => EnsureEmailIsVerified::class,
]);
// Add to existing group
$middleware->appendToGroup('web', [
ShareDataWithViews::class,
]);
$middleware->appendToGroup('api', [
EnsureApiKey::class,
]);
// Middleware priority
$middleware->priority([
TrustProxies::class,
HandleCors::class,
StartSession::class,
Authenticate::class,
]);
})->create();
3. Applying Middleware to Routes
use Illuminate\Support\Facades\Route;
// Single route
Route::get('/admin', AdminController::class)->middleware('auth', 'role:admin');
// Route group
Route::middleware(['auth', 'verified'])->group(function () {
Route::resource('articles', ArticleController::class);
Route::get('/dashboard', DashboardController::class);
});
// Nested groups
Route::prefix('admin')->middleware(['auth', 'role:admin'])->name('admin.')->group(function () {
Route::resource('users', AdminUserController::class);
Route::resource('settings', SettingController::class);
});
// Controller middleware (Laravel 11 constructor middleware)
class ArticleController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
$this->middleware('throttle:10,1')->only(['store', 'update', 'destroy']);
}
}
4. Terminable Middleware
class LogResponseTime implements TerminableMiddleware
{
private float $startTime;
public function handle(Request $request, Closure $next): Response
{
$this->startTime = microtime(true);
return $next($request);
}
// Called after response is sent to client
public function terminate(Request $request, Response $response): void
{
$duration = (microtime(true) - $this->startTime) * 1000;
RequestLog::create([
'method' => $request->method(),
'path' => $request->path(),
'status' => $response->getStatusCode(),
'duration' => round($duration),
'ip' => $request->ip(),
]);
}
}
5. Common Middleware Patterns
// Force HTTPS in production
class ForceHttps
{
public function handle(Request $request, Closure $next): Response
{
if (! $request->secure() && app()->environment('production')) {
return redirect()->secure($request->getRequestUri(), 301);
}
return $next($request);
}
}
// Set locale from URL segment
class SetLocale
{
public function handle(Request $request, Closure $next): Response
{
$locale = $request->segment(1);
if (in_array($locale, config('app.supported_locales'))) {
app()->setLocale($locale);
}
return $next($request);
}
}
6. Built-in Middleware Reference
| Class / Alias | Purpose |
|---|---|
| auth | Authenticate user |
| auth:api | Authenticate via API guard |
| throttle:60,1 | Rate limit (60 req/min) |
| verified | Email must be verified |
| signed | Validate signed URL |
| can:update,article | Authorization gate |
| cache.headers | Set HTTP cache headers |
| ValidateSignature | Signed routes |
| HandleCors | Cross-Origin headers |