| name | middleware |
| description | HTTP request/response pipeline handlers that inspect, modify, or reject requests before or after they reach a controller. Used for authentication, throttling, header manipulation, and logging. |
| compatible_agents | ["implement","refactor","review"] |
Middleware
When to Apply
- Use for cross-cutting HTTP concerns: authentication gates, throttling, headers, request correlation IDs.
- Use when logic must run before controller execution or after response creation.
- Prefer group/global middleware for repeated behavior across many routes.
- Do not use for model authorization (Policies), request body validation (Form Requests), or domain business rules (Actions/Services).
Preconditions
- Middleware class path exists:
app/Http/Middleware/.
- Registration point is available in
bootstrap/app.php (->withMiddleware(...) for Laravel 11+).
- The behavior is request/response pipeline logic, not model/domain behavior.
Process
1. Create a Focused Middleware Class
- Use a specific name (
EnsureUserIsSubscribed, ForceJsonResponse).
- Implement
handle(Request $request, Closure $next): Response.
- Return early on rejection, otherwise call
$next($request).
2. Decide Scope: Global vs Group vs Route
- Global (
append) for behavior required on every request.
- Group/alias for feature-level behavior reused across routes.
- Route-level only for exceptional one-off cases.
3. Register in bootstrap/app.php
- Register global or alias entries in
->withMiddleware(...).
- Apply aliases on route groups when possible.
4. Test Behavior
- Use feature tests with middleware enabled for expected responses.
- Use
$this->withoutMiddleware() only when isolating unrelated controller behavior.
Examples
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserIsSubscribed
{
public function handle(Request $request, Closure $next): Response
{
if (!$request->user()?->isSubscribed()) {
return response()->json(['message' => 'Subscription required.'], 403);
}
return $next($request);
}
}
public function handle(Request $request, Closure $next): Response
{
$request->headers->set('X-Request-Id', Str::uuid());
$response = $next($request);
$response->headers->set('X-Powered-By', 'MyApp');
return $response;
}
->withMiddleware(function (Middleware $middleware) {
$middleware->append(ForceJsonResponse::class);
$middleware->alias([
'subscribed' => EnsureUserIsSubscribed::class,
]);
})
Route::middleware('subscribed')->group(function () {
Route::get('/dashboard', DashboardController::class);
});
Checklists
Anti-Patterns
- Putting business logic inside middleware (belongs in Actions or Services)
- Putting model-level authorization in middleware (belongs in Policies)
- Validating the request body in middleware (belongs in Form Requests)
- Accessing validated input inside middleware — middleware runs before validation
- Using middleware for things that only apply to a single route
References
- Laravel Middleware
- Laravel HTTP Tests
resources/boost/skills/policies/SKILL.md (authorization boundaries)
resources/boost/skills/formrequests/SKILL.md (request validation boundaries)