Search code examples
phplaravelpusherbroadcasting

How to configure Channel Authorization for Broadcasting in Laravel 5.3 using Pusher Driver?


  • Laravel Version: 5.3.*
  • PHP Version: 5.6.17
  • Database Driver & Version: mysql

Description:

According to Laravel 5.3 documentation when broadcasting events on private or presence channels, in the boot method of the BroadcastServiceProvider one must provide a callback that resolves if an user has authorization to listen to that channel to the Broadcast facade method channel. This method should return a boolean. In the the BroadcastServiceProvider method boot we should also include Broadcast::routes() that will define the auth route that the client will call to check for permission on the channel. This routes method can receive an array of attributes to apply to the route. Now it's where it gets weird. When the client call this route no matter what callback I passed to the Broadcast::channel method it will give me a 403 forbidden unless (and now comes the weirdest part) I provide an array to the Broadcast::routes with a key named prefix and a value of whatever. If the key is not prefix it will go back to 403 forbidden.

HttpException in PusherBroadcaster.php line 42:

My setup follows. I'm for sure doing something wrong but after a lot of ours trying to understand I can't figure it out. Can someone give an hint?

Steps To Reproduce:

I have created a simple event:

<?php

namespace App\Events;

use App\Models\Presentation;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class PresentationCreated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public $presentation;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(Presentation $presentation)
    {
        $this->presentation = $presentation;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('presentation');
    }
}

that i trigger by calling event(new PresentationCreated($presentation));

I have installed "pusher/pusher-php-server": "^2.5.0" and created an account in pusher. I put my pusher credentials in .env:

BROADCAST_DRIVER=pusher
PUSHER_APP_ID=*****
PUSHER_APP_KEY=*****************
PUSHER_APP_SECRET=****************
PUSHER_APP_CLUSTER=**

in my config\broadcast.php I have:

'pusher' => [
        'driver' => 'pusher',
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'app_id' => env('PUSHER_APP_ID'),
        'options' => [
          'cluster' => 'eu',
          'encrypted' => true,
        ],
    ],

My client side:

this.Echo = new Echo({
            broadcaster: 'pusher',
            key: typeof handover.pak !== 'undefined' ? handover.pak : '',
            cluster: 'eu'
        });

        this.Echo.private(`presentation`)
        .listen('PresentationCreated', (e) => {
            console.log(e, 'raposa')
        });

And finally the BroadcastServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes();

        //The commented line would make the authorization pass even if I return false bellow
        //Broadcast::routes(['prefix' => 'I do not know what I am doing']);

        /*
         * Authenticate the user's personal channel...
         */
        Broadcast::channel('presentation', function ($user) {
            return false;
        });
    }
}

EDIT

Thanks to @yazfield answer I was able to understand what was going on. The http error was due to the $request->user() being null. That was because I was not passing the additional middlewares that my route namespace was using. By doing Broadcast::routes(['middleware' => ['web', 'clumsy', 'admin-extra']]); I was able to solve the problem.

This Laravel issue also helped me getting the grasp of the thing.


Solution

  • By giving a parameter to routes you're setting routes attributes and overriding the attributes that default to 'middleware' => ['web'], which basically means you're not using any of the web middlewares when you give any array without middleware attribute, you're not verifying crsfToken...etc.