Laravel Middleware Parameters & Terminable Middleware
Middleware in Laravel is a powerful way to filter HTTP requests entering your application. In this tutorial, we’ll explore two advanced middleware features:
- Passing Parameters to Middleware
- Terminable Middleware (running code after response is sent)
Middleware Parameters
Sometimes, your middleware needs extra information to decide what to do. For example, let’s say we want to check if a user has a specific role before accessing a route.
Step 1: Create Middleware
Run the Artisan command:
php artisan make:middleware EnsureUserHasRole
This creates a file in app/Http/Middleware/EnsureUserHasRole.php.
Step 2: Add Logic with Parameters
Update the handle() method to accept an extra $role parameter:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserHasRole
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user() || ! $request->user()->hasRole($role)) {
// Redirect or throw 403 if user doesn’t have role
abort(403, 'Unauthorized');
}
return $next($request);
}
}
Here:
$rolewill be passed from the route definition.- We check if the logged-in user has that role. If not, we block the request.
Step 3: Use Middleware in Route
You can now pass parameters when applying middleware to routes:
Example: Single Role
use App\Http\Middleware\EnsureUserHasRole;
Route::put('/post/{id}', function (string $id) {
// Only "editor" role can update posts
})->middleware(EnsureUserHasRole::class . ':editor');
Example: Multiple Roles
Route::put('/post/{id}', function (string $id) {
// User must be "editor" OR "publisher"
})->middleware(EnsureUserHasRole::class . ':editor,publisher');
Here, multiple parameters are separated by commas.
Terminable Middleware
Sometimes you need middleware to run after the response is sent to the user (e.g., logging, cleanup, analytics). This is where terminable middleware comes in.
Step 1: Create Middleware
php artisan make:middleware TerminatingMiddleware
Step 2: Add terminate() Method
Modify the file:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class TerminatingMiddleware
{
/**
* Handle the request before response is sent.
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
/**
* Handle tasks after the response is sent.
*/
public function terminate(Request $request, Response $response): void
{
// Example: log user activity
\Log::info('Request completed for user: ' . ($request->user()->id ?? 'guest'));
}
}
handle()runs before sending response.terminate()runs after response is sent to browser (requires FastCGI or queue worker).
Step 3: Register Middleware
Add your middleware in bootstrap/app.php or assign it to routes.
use App\Http\Middleware\TerminatingMiddleware;
$app->middleware([
TerminatingMiddleware::class,
]);
Step 4: Use Singleton (Optional)
By default, Laravel will create a new instance of the middleware when calling terminate().
If you want to use the same instance for both handle() and terminate(), register it as a singleton in AppServiceProvider:
use App\Http\Middleware\TerminatingMiddleware;
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}
Important
- Middleware Parameters let you pass custom values (like roles) into middleware from your routes.
- Terminable Middleware lets you run code even after the response is sent, great for logging, analytics, or background tasks.
With these, you can make your Laravel app more secure and more powerful.
