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 inline max,minutes.
  • CSRF protection: PreventRequestForgery (renamed from VerifyCsrfToken in Laravel 13) runs on non-GET routes; Blade's @csrf renders the hidden token field.
  • signed: Validates the signature on URLs generated by URL::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:

php
use 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:

php
Route::get('/settings/security', [SecurityController::class, 'index'])
    ->middleware(['auth', 'password.confirm']);

// User must confirm password within last 3 hours (default)

Verified Email Middleware

php
Route::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:

php
Route::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

  1. Forgetting @csrf in Blade forms — POST, PUT, PATCH, DELETE routes reject any request without a token.
  2. Mixing auth and guest by accident — guest redirects authenticated users away; do not add it to authenticated routes.

Best Practices

  1. Use named rate limiters — Define RateLimiter::for('api', ...) and attach with throttle:api.
  2. Combine middleware in groups — Route::middleware(['auth', 'verified'])->group(...) replaces repetition.

Summary

  • auth protects logged-in routes; guest protects guest-only routes.
  • throttle rate-limits by user or IP, using named limiters or inline values.
  • @csrf is required in every Blade form for POST/PUT/PATCH/DELETE routes.
  • signed validates signed URLs.
  • Maintenance mode is controlled with php artisan down/up.
✓ Completed