Authentication, CSRF, rate limiting and logging all run as middleware around your controllers.
Middleware wraps request handling: each layer receives the request, can stop it early (redirect, 403, 429) or pass it on with $next($request), and can modify the response on the way back. Requests flow through the stack like an onion.
Generate one with php artisan make:middleware EnsureUserIsSubscribed:
public function handle(Request $request, Closure $next): Response
{
if (! $request->user()?->subscribed()) {
return redirect('/billing');
}
return $next($request);
}Code before $next() runs on the way in; code after it can change the response.
Register and apply it:
- On routes:
->middleware(EnsureUserIsSubscribed::class), or a short alias defined inbootstrap/app.phpwith$middleware->alias(['subscribed' => ...]). - Globally:
$middleware->append(...)inbootstrap/app.php, or add to a group with$middleware->web(append: [...]). - Parameters:
->middleware('role:editor')passes'editor'as an extra argument tohandle.
Laravel ships middleware for the web group (sessions, cookies, CSRF verification) and common aliases: auth, guest, verified, throttle:60,1, can:update,post and signed.
A terminable middleware defines terminate($request, $response), which runs after the response is sent, for logging or cleanup that shouldn't delay the user.
Example
<?php
// app/Http/Middleware/AddRequestId.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class AddRequestId
{
public function handle(Request $request, Closure $next): Response
{
$id = $request->header('X-Request-Id') ?? (string) Str::uuid();
$request->attributes->set('request_id', $id); // before
$response = $next($request);
$response->headers->set('X-Request-Id', $id); // after
return $response;
}
}
// bootstrap/app.php
// ->withMiddleware(function (Middleware $middleware) {
// $middleware->append(AddRequestId::class); // every request
// $middleware->alias(['subscribed' => EnsureUserIsSubscribed::class]);
// })
// routes/web.php: Route::get('/reports', ...)->middleware(['auth', 'subscribed', 'throttle:30,1']);Remember
- Middleware runs before and after the handler around $next($request)
- Register globally, in groups or by alias in bootstrap/app.php
- Built-ins include auth, throttle, can and signed
Watch out for
- Forgetting to return $next($request), which ends the request with an empty response.