# Adding shared behavior to requests with Laravel middleware

> What middleware is in Laravel, how to write it, and how to centralize cross-cutting concerns like authentication in one place.

- Published: 2015-10-04
- Category: Framework & Library
- Tags: Laravel
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/adding-shared-behavior-to-requests-with-laravel-middleware/
- Language: en-US
- Author: Muhammet Şafak

---
You want only authenticated users to access certain routes in a Laravel project. The classic approach is adding a check to every controller method:

```php
public function panel()
{
    if (!Auth::check()) {
        return redirect('/giris');
    }

    // ... actual code
}
```

This works. But once you have five controllers and twenty methods, you are repeating the same code in twenty places. When something needs to change, you need to update all twenty spots.

**Middleware** is the way to centralize these kinds of cross-cutting concerns — behaviors that repeat on every request, like authentication, authorization, request logging, and locale detection — into a single place. It sits between the HTTP request and the controller, and it can inspect and modify the request, or stop it entirely.

## How middleware works

When a request arrives in Laravel, it passes through a middleware chain. Each middleware either passes the request to the next step or returns a response to break the chain. Think of it as a series of gates — each gate inspects the request.

[Laravel 5](/en/blog/migrating-to-laravel-5-directory-structure-and-env/) ships with several built-in middleware: `Authenticate` (authentication), `VerifyCsrfToken` (CSRF protection), `RedirectIfAuthenticated` (redirect if already logged in). These live under `app/Http/Middleware/`.

## Writing your own middleware

```bash
php artisan make:middleware GirisKontrol
```

This command creates `app/Http/Middleware/GirisKontrol.php`:

```php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class GirisKontrol
{
    public function handle($request, Closure $next)
    {
        if (!Auth::check()) {
            return redirect('/giris');
        }

        return $next($request);
    }
}
```

The `handle` method takes two parameters: the incoming request and a closure we call `$next`. Calling `$next($request)` passes the request to the next step. When the condition is not met, `$next` is never called and the chain is broken.

## Registering middleware

To use the middleware you have written, you need to register it in `app/Http/Kernel.php` by assigning it a short alias:

```php
protected $routeMiddleware = [
    'auth'    => \App\Http\Middleware\Authenticate::class,
    'giris'   => \App\Http\Middleware\GirisKontrol::class,
    // ...
];
```

## Applying it to routes

For a single route:

```php
Route::get('/panel', 'PanelController@index')->middleware('giris');
```

For multiple routes using a group:

```php
Route::group(['middleware' => 'giris'], function () {
    Route::get('/panel',    'PanelController@index');
    Route::get('/profil',   'ProfilController@index');
    Route::get('/ayarlar',  'AyarlarController@index');
});
```

Every route added to this group automatically passes through the `giris` middleware. You do not need to write any control code when adding a new route to the group.

## Using middleware in a controller constructor

You can also specify middleware at the controller level rather than in the route:

```php
class PanelController extends Controller
{
    public function __construct()
    {
        $this->middleware('giris');
    }
}
```

If you want to apply it only to specific methods:

```php
$this->middleware('giris', ['only' => ['index', 'goster']]);
$this->middleware('giris', ['except' => ['hakkinda']]);
```

There is a subtle difference between defining middleware in a controller constructor versus in a route group: controller-level middleware covers all routes belonging to that controller — even if you forget to add the middleware in the route definition. But when you add a new controller to a route group, you need to remember to include it in the group. Which approach is more reliable depends on the structure of your project.

## After-response middleware

Middleware can run not only before the request is handled, but also after the response has been sent. To do this, process the response after calling `$next`:

```php
public function handle($request, Closure $next)
{
    $yanit = $next($request);

    // Add a header to the response
    $yanit->headers->set('X-Uygulama', 'benimsite');

    return $yanit;
}
```

Request logging, adding response headers, and performance measurement all use this pattern.

## Middleware with parameters

You can also pass parameters to middleware. For example, a role check:

```php
public function handle($request, Closure $next, $rol)
{
    if (!$request->user()->hasRole($rol)) {
        abort(403);
    }

    return $next($request);
}
```

It is used on a route as `middleware('rol:admin')`. For multiple parameters, separate them with commas: `middleware('rol:admin,editor')`. In the handle method, these parameters arrive as additional arguments.

## Chaining multiple middleware

You can apply more than one middleware to a route:

```php
Route::get('/admin/panel', 'AdminController@index')
     ->middleware(['giris', 'rol:admin']);
```

Middleware runs in order. If the `giris` check fails, `rol:admin` never runs. This ordering matters: authentication first, then authorization. The other way around, `$request->user()` could return null for an unauthenticated user and the role check would throw an error.

Once you internalize the middleware concept, you naturally want to clean up all the repeated control code scattered across controllers. Authentication, locale detection, request logging — these behaviors belong here. Controller methods can then focus on the actual work.
