Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
        }
    }
});
like image 980
southpaw93 Avatar asked Dec 23 '22 04:12

southpaw93


2 Answers

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.

like image 109
Cy Rossignol Avatar answered Dec 25 '22 16:12

Cy Rossignol


I actually managed to find a solution, so all I needed to do was bind the $user that I got in my custom auth middleware to the request by doing the following thing:

$request->merge(['user' => $user]);

//add this
$request->setUserResolver(function () use ($user) {
   return $user;
});

and now $request->user() which laravel checks returns the user object and passes the validation.

like image 29
southpaw93 Avatar answered Dec 25 '22 16:12

southpaw93