Search code examples
phplaravelbroadcastlaravel-5.6pusher

How to change Laravel's default broadcast auth middleware


So, as my title says, I want to change Laravel's default Broadcast auth middleware to a custom auth middleware that I made which uses token-based authentication. I made this because my app is an API-based app, and, when a user authenticates, I create a session token and send it to him and also store it inside the DB with an expires_at column. I am using Pusher.

I have the following middleware:

class AuthCustom
{
    public function handle($request, Closure $next)
    {
        // if we have the session token stored in header
        if ($request->header('x-session')) {
            $session = Session::where('id', $request->header('x-session'))->where('expires_on', '>=', date('Y-m-d G:i:s'))->with('user')->first();
            if ($session !== null) {
                $user = (new User())->where('id', $session->user_id)->first();
                if ($user !== null) {
                    $request->merge(['user' => $user]);

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

My BroadcastServiceProvider code is as follows:

class BroadcastServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Broadcast::routes();

        require base_path('routes/channels.php');
    }
}

If I put Broadcast::routes(['middleware' => 'authcustom']); in BroadcastServiceProvider, the boradcasting/auth gives a 403 status code because $request->user() is null, which then results in an Access forbidden.

I have tried searching the whole damn web, and I found nothing about changing the default auth middleware for broadcasting.

I even tried removing Broadcast::routes() and customizing a new route /broadcast which returned a Pusher socket_auth object and everytime I got a 419 Unkown status code.

Any ideas or maybe you can point me in the direction where I could manage this? Thank you!

Later edit: My JS Echo connection looks like this:

Vue.use(VueEcho, {
    broadcaster: 'pusher',
    key: 'xxxxxxxxxxxxxx',
    cluster: 'eu',
    authEndpoint: 'http://localhost/api.easycargo.ro/public/broadcasting/auth',
    auth: {
        headers: {
            'x-session': this.auth.token
        }
    }
});

Solution

  • I'm glad you got something working. For later readers, here's a more Laravel-esque way to solve the problem in the question: create a custom auth guard used to authenticate requests for the special routes.

    Laravel's AuthManager includes a helper method—viaRequest()—that simplifies the creation of a Guard that authenticates a user with data from the request context without the need to fully-implement Illuminate\Contracts\Auth\Guard. We can bind our custom guard in the boot() method in AuthServiceProvider.php:

    public function boot()
    {
        Auth::viaRequest('custom-auth', function ($request) {
            // Any custom user-lookup logic here. For example:
            if ($request->header('x-session')) {
                $user = // ...try to fetch a user...
                return $user;
            }
        });
    }
    

    As we can see, we just pass a closure to the viaRequest() method that returns a User object when authentication succeeds, or null when authentication fails.

    Next, we'll tell Laravel about our new auth guard by adding an entry to the 'guards' array in config/auth.php:

    'guards' => [ 
        ...
        'broadcasting' => [
            'driver' => 'custom-auth', 
        ],
    ],
    

    Finally, we need to update the middleware for any routes that should authenticate a user with our custom Guard. We can use Laravel's built-in auth middleware and specify which guard to apply as a middleware parameter. For example, we'll initialize the broadcasting routes in the question's BroadcastServiceProvider.php:

    Broadcast::routes([ 'middleware' => [ 'auth:broadcasting', ... ] ]);
    

    ...where broadcasting matches the name we assigned to our custom Guard in config/auth.php.

    This approach enables us to use all of Laravel's Auth services, provides a more central place to define our authentication logic, and simplifes automated testing because we can more easily mock up authentication as needed.