Mastering Laravel Middleware – Part 3

aravel Laravel Views & Blade Templates – Beginner’s Guide

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:

  1. Passing Parameters to Middleware
  2. 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:

  • $role will 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.