Introduction
Laravel ships a toolbox of middleware that cover 90% of everyday needs: auth, guest, throttle, CSRF protection, signed URL validation, verified email, maintenance mode. This lesson walks through each one so you recognise them in any routes file.
Key Concepts
auth/guest: Mutually exclusive — one requires a logged-in user, the other requires none.throttle: Rate-limits by IP or authenticated user. Accepts a named limiter or inlinemax,minutes.- CSRF protection:
PreventRequestForgery(renamed fromVerifyCsrfTokenin Laravel 13) runs on non-GET routes; Blade's@csrfrenders the hidden token field. signed: Validates the signature on URLs generated byURL::signedRoute.verified: Gates routes on a verified email address.
Real World Context
Every Laravel application uses auth, throttle, and CSRF without even thinking about it. Knowing which middleware is built-in saves you from reimplementing features Laravel already ships.
Deep Dive
Laravel includes several middleware out of the box that handle common web application needs. Understanding these helps you build secure, robust applications.
Authentication Middleware
The auth middleware redirects guests to the login page:
php// Require authentication Route::get('/dashboard', DashboardController::class) ->middleware('auth'); // Specify a guard Route::get('/admin', AdminController::class) ->middleware('auth:admin'); // Multiple guards Route::get('/api/user', fn() => auth()->user()) ->middleware('auth:sanctum,api');
Guest Middleware
The guest middleware redirects authenticated users:
php// Only for guests (not logged in) Route::get('/login', [LoginController::class, 'showLoginForm']) ->middleware('guest'); Route::get('/register', [RegisterController::class, 'showRegistrationForm']) ->middleware('guest');
Throttle Middleware (Rate Limiting)
Prevent abuse with rate limiting:
php// 60 requests per minute Route::get('/api/data', DataController::class) ->middleware('throttle:60,1'); // Named rate limiter Route::get('/api/data', DataController::class) ->middleware('throttle:api');
Define custom rate limiters in AppServiceProvider:
phpuse Illuminate\Cache\RateLimiting\Limit; use Illuminate\Support\Facades\RateLimiter; public function boot(): void { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); RateLimiter::for('uploads', function (Request $request) { return $request->user()?->isPremium() ? Limit::none() : Limit::perMinute(10)->by($request->user()->id); }); }
CSRF Protection
The PreventRequestForgery middleware (renamed from VerifyCsrfToken in Laravel 13 and now origin-aware) protects against cross-site request forgery. It is included in the default web group:
blade<!-- Include CSRF token in forms --> <form method="POST" action="/users"> @csrf <!-- Adds hidden _token field --> <input type="text" name="name"> <button type="submit">Submit</button> </form>
Exclude routes from CSRF protection in bootstrap/app.php — typical for webhook endpoints that cannot provide a token:
php->withMiddleware(function (Middleware $middleware) { $middleware->preventRequestForgery(except: [ 'stripe/*', 'webhook/*', ]); })
Signed URL Middleware
Validate signed URLs:
php// Generate signed URL $url = URL::signedRoute('unsubscribe', ['user' => 1]); // Validate with middleware Route::get('/unsubscribe/{user}', [UnsubscribeController::class, 'handle']) ->name('unsubscribe') ->middleware('signed');
Password Confirmation Middleware
Require password re-entry for sensitive actions:
phpRoute::get('/settings/security', [SecurityController::class, 'index']) ->middleware(['auth', 'password.confirm']); // User must confirm password within last 3 hours (default)
Verified Email Middleware
phpRoute::get('/dashboard', DashboardController::class) ->middleware(['auth', 'verified']); // Unverified users are redirected to email verification notice
Maintenance Mode Middleware
PreventRequestsDuringMaintenance redirects to maintenance page:
bash# Enable maintenance mode php artisan down # Allow specific IPs php artisan down --allow=192.168.1.1 # With secret bypass php artisan down --secret="bypass-token" # Visit /bypass-token to get a cookie that bypasses maintenance
Cache Headers Middleware
Add caching headers to responses:
phpRoute::get('/static-page', StaticController::class) ->middleware('cache.headers:public;max_age=2628000;etag');
Practical Example: Combining Middleware
php// API routes with multiple protections Route::prefix('api/v1') ->middleware(['api', 'auth:sanctum', 'throttle:api']) ->group(function () { Route::get('/user', fn(Request $request) => $request->user()); Route::apiResource('posts', PostController::class); // Premium features with different throttle Route::middleware('throttle:premium') ->group(function () { Route::post('/analyze', AnalyzeController::class); }); }); // Admin routes with multiple guards Route::prefix('admin') ->middleware(['auth', 'verified', 'password.confirm']) ->group(function () { Route::get('/dashboard', [AdminController::class, 'dashboard']); // Extra protection for dangerous actions Route::delete('/users/{user}', [AdminController::class, 'destroyUser']) ->middleware('can:delete-users'); });
Common Pitfalls
- Forgetting
@csrfin Blade forms — POST, PUT, PATCH, DELETE routes reject any request without a token. - Mixing
authandguestby accident —guestredirects authenticated users away; do not add it to authenticated routes.
Best Practices
- Use named rate limiters — Define
RateLimiter::for('api', ...)and attach withthrottle:api. - Combine middleware in groups —
Route::middleware(['auth', 'verified'])->group(...)replaces repetition.
Summary
authprotects logged-in routes;guestprotects guest-only routes.throttlerate-limits by user or IP, using named limiters or inline values.@csrfis required in every Blade form for POST/PUT/PATCH/DELETE routes.signedvalidates signed URLs.- Maintenance mode is controlled with
php artisan down/up.