Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

rovansteen's avatar

Register middleware via service provider

Is there any way I can register a middleware through a package? According to the documentation the only way to register a middleware is by adding it to the array in the App\Http\Kernel class.

Since the application bootstraps by resolving the Http\Kernel contract from the IoC container I tried to switch it out with my own kernel inside the package, but no luck. It seems that it resolves it before registering the service providers from my package.

Is there any way to accomplish this?

0 likes
36 replies
usman's avatar

Not sure if it is possible to add global middlewares, but you can achieve some thing similar using before/after global filters and route level middlewares . In your package service provider you can apply them inside the boot method using:

$router = $this->app['router'];

$router->before(BeforeGlobalFilter::class);
$router->after(AfterGlobalFilter::class);

//also you can register your route level middlewares using the router
$router->middleware('key', MiddlewareClass::class);

Usman.

1 like
usman's avatar

@blackbird this article is pretty much outdated. middleware method has been removed from the Application class.

usman's avatar

@blackbird they are requiring us to do it manually:

Step 1: Add to stack

// App\Http\Kernel.php
protected $stack = [
    ...
    'Sheepy85\L5Localization\Middleware\Localization',
];

Also I don't think they have updated it after the release of Laravel 5. $stack has also been renamed to $middleware.

nolros's avatar

@Rovansteen and @usman why can't you just decorator the Middleware interface and then create a ServiceProvider to bind your own middleware?

  1. create your own decorator off the Middleware interface
use Closure;
use Illuminate\Contracts\Routing\Middleware;

class RovansteenMiddlewareDecorator implements Middleware {
// your code

  1. Create your own ServiceProvider
// must extend GeneratorServiceProvider
use Illuminate\Routing\GeneratorServiceProvider as ServiceProvider;
use Illuminate\Routing\Console\MiddlewareMakeCommand;
use Illuminate\Routing\Console\ControllerMakeCommand;

class RovansteenServiceProvider extends ServiceProvider { 

    /**
     * Register the middleware generator command.
     *
     * @return void
     */
    protected function register()
    {
        $this->app->singleton('command.middleware.make', function($app)
        {
            // and I'm pulling this out the air but you get the idea
            // the middleware command syntax can be found at Illuminate\Routing\Console;
            $myMiddleWareCommand // get from config, static class, user input, build etc

            // now as I've not tested it you might be able to pull $app['files'] into your own method and manipulate 
            // prior to passing it through  
            // OR depending on what $app['files'] is you could pass through your own command and then inject
            $middleware = new MiddlewareMakeCommand($app['files']);
            
            // obviously the syntax would match your decorator construct, but it would require an instance of $middleware
            return new RovansteenMiddlewareDecorator($middleware , $myMiddleWareCommand );
        });
    }

}
rovansteen's avatar

The thing is that it the service providers are loaded after the Kernel is resolved and handles the request. So I'm guessing there is no way to decorate or intercept the global middleware, without modifying the stack manually in the App\Http\Kernel, because that's hardcoded in the index.php file in the application.

nolros's avatar

@Rovansteen agreed, they are not eager or deferred loaded as with providers, but it depends on what you are attempting to do with the request and then how you intend to inject it the application. However the kernel is loading middleware with its own calls and what I'm suggesting is tapping into those so that Laravel kernel makes the call and you decorate the receiving class. Take a look at

class GeneratorServiceProvider extends ServiceProvider {

Laravel loads middleware through the MiddlewareMakeCommand() and as such I'm suggesting decorating the middleware and extending that Generator SP and then latching yoru own register methods onto your SP decorator, if you will. If that makes sense.

rovansteen's avatar

How am I supposed to tap in to the Kernel if it's loaded before my own service provider runs? Also it seems that GeneratorServiceProvider is not running on HTTP requests. If I var_dump something from it's register method it shows up when I run an artisan command, but not with a HTTP request.

I'm guessing Taylor has set it up this way to have a kernel that is really specific for each type of request so that the Http Kernel can't be swapped out from another place.

bestmomo's avatar
Level 52

Simplicity : ask user to manualy add it in middleware stack, as you do for provider.

3 likes
usman's avatar

Updated Solution://

Since all the middlewares are resolved through IoC, as a last work around you can replace one of the available middlewares with your custom functionality:

use Closure;
use Illuminate\Contracts\Foundation\Application;
use Symfony\Component\HttpKernel\Exception\HttpException;

class PackageMiddleware {

    protected $app;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    public function handle($request, Closure $next)
    {
        if ($this->app->isDownForMaintenance())
        {
            throw new HttpException(503);
        }

        //do your thing here.
        //
        return $next($request);
    }
}

And then add a binding inside your package service provider:

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app->singleton('Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode', function($app){

            return  new PackageMiddleware($app);
                
        });
    }

Usman.

rovansteen's avatar

@pmall I'm planning to make a package for API's I can use for different projects. @usman thanks for your solution. Unfortunately it does feel 'hacky' to use an existing middleware for different purposes, but thanks anyway.

usman's avatar

Simplicity : ask user to manualy add it in middleware stack, as you do for provider.

This is indeed the right way to go.

Yes, that was hacky, the idea was to convey the message " there is no other solution ".

1 like
pmall's avatar

I'm planning to make a package for API's I can use for different projects.

What is its functionality ?

rovansteen's avatar

@pmall my company wrote a package for L4 that automatically sets up routes for the models including relationships, allows for different types of responses (json, xml etc) and lots of other stuff that's needed for an API. But it involved quite some 'nasty' hacking in L4 so with the new L5 middleware we are looking to rewrite it in a more clean and elegant way.

pmall's avatar

Not sure it really belongs to a middleware

rovansteen's avatar

Why is that?

From the Laravel 5 middleware docs: "Of course, middleware can be written to perform a variety of tasks besides authentication. A CORS middleware might be responsible for adding the proper headers to all responses leaving your application. A logging middleware might log all incoming requests to your application."

So, setting the content type for application/json for example seems to be something you use middleware for.

pmall's avatar

So, setting the content type for application/json for example seems to be something you use middleware for.

Yes sure. Maybe I didn't understood what you want to do. but response()->json() will do this for you.

But sometimes people put everything in middleware whereas other laravel features are made for what they need.

rovansteen's avatar

Yes, I understand that. But to let the magic of the package do it work it needs to 'tap' in to the request lifecycle. Therefore the middleware seems to me the correct place to do so.

davidnknight's avatar

You might not always want to ask a user to add middleware manually to the Kernel, I certainly didn't want to do that, I wanted to register them in a package so that it's more plug and play, and essentially the package wouldn't work without the middleware being registered.

So, here it is:

<?php namespace Vendor\Package\Providers;

use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * All of the short-hand keys for middlewares.
     *
     * @var array
     */
    protected $middleware = [
        'middlewareName' => 'Vendor\Package\Http\Middlewares\Middleware'
    ];

    /**
     * Bootstrap any application services.
     *
     * @param  \Illuminate\Routing\Router  $router
     * @return void
     */
    public function boot(Router $router)
    {
        parent::boot($router);

        foreach($this->middleware as $name => $class) {
            $this->middleware($name, $class);
        }
    }

    ...
}
?>

$this->middleware() calls a magic method (__call()) on the RouteServiceProvider which in turn calls a method on the Router in which you can register middleware. You could have also done $router->middleware() since Router $router is injected into the boot method, either that or $this works.

Now you don't have to manually add it to the Kernel. =)

usman's avatar

@davidnknight Hmm, we have already discussed this option. See my very first reply on the first page :)

Usman.

lucifurious's avatar

I just ran into this issue and have a simple solution that does not require the user to modify configuration files.

In the boot method of my service provider, I simply create the binding to my middleware:

    /** @inheritdoc */
    public function boot()
    {
        $_configPath = realpath(__DIR__ . '/../../config');
        $_configFile = $_configPath . DIRECTORY_SEPARATOR . 'partner.php';
        $_routeFile = $_configPath . DIRECTORY_SEPARATOR . 'routes.php';

        //  Add our routes...
        if (file_exists($_routeFile)) {

            $this->singleton('auth.partner', function ($app) {
                return new AuthenticatePartner($app);
            });

            /** @noinspection PhpIncludeInspection */
            include $_routeFile;
        }

        //  Config
        if (file_exists($_configFile)) {
            $this->publishes([$_configFile => config_path('partner.php'),], 'config');
        }
    }

You see I register auth.partner in the IoC. So the next bit includes my routes.php file that is included with my service:

    \Route::group(['middleware' => 'auth.partner'], function () {
        \Route::resource('partner', 'PartnerController');
    });

Here I'm simply specifying the middleware for a group, then my controller is nestled inside comfortably. Works great.

This is 5.1 btw

1 like
crynobone's avatar

You can easily do it in any service provider (boot would be a nice place since we can use method based DI).

public function boot(\Illuminate\Contracts\Http\Kernel $kernel) {
     $kernel->appendMiddleware('Sheepy85\L5Localization\Middleware\Localization'); // prependMiddleware works too.
}
5 likes
gmlo89's avatar

You can do this on Laravel 5.1 Example:

public function boot(Illuminate\Routing\Router $router)
    {
        $router->middleware('custom_auth', 'Path\To\Your\Middleware\custom_auth');
    }
7 likes
kJamesy's avatar

Just a note on gmlo89's answer, the second argument is your namespaced class:

$router->middleware('manage_content',  \Kjamesy\Cms\Middleware\ManageContentMiddleware::class);
2 likes
Next

Please or to participate in this conversation.