Install pusher
composer require pusher/pusher-php-server
Add environment variables
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=//not needed
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
Make sure you change the Broadcast driver to pusher
BROADCAST_DRIVER=pusher
Go to “config/app.php” and uncomment the following line:
App\Providers\BroadcastServiceProvider::class,
Create an Event
php artisan make:event MessageReceived
Inside of Event class
<?php
namespace App\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessageReceived implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $account_id;
public $conversation_id;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($account_id, $conversation_id, $message)
{
$this->message = $message;
$this->account_id = $account_id;
$this->conversation_id = $conversation_id;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('account.' . $this->account_id);
}
public function broadcastAs()
{
return 'message-received';
}
}
Create endpoint for Pusher to authenthicate with Laravel Passport
/**
* Authenticates logged-in user in the Pusher JS app
* For private channels
* @throws PusherException
*/
public function pusherAuth(Request $request)
{
parse_str($request->getContent(), $output);
$user = auth()->user();
if($output['channel_name'] !== 'private-account.' . $user->account_id){
return response([
'message' => 'Not authorized to access this channel'
], 403);
}
$key = env('PUSHER_APP_KEY');
$secret = env('PUSHER_APP_SECRET');
$app_id = env('PUSHER_APP_ID');
if ($user) {
$pusher = new Pusher($key, $secret, $app_id);
$auth = $pusher->authorizeChannel($output['channel_name'], $output['socket_id']);
return response($auth, 200);
} else {
return response([
'message' => 'Not authorized to access this channel'
], 403);
}
}
Add route to function created above
Route::post('pusher', [AuthController::class, 'pusherAuth']);
Have Javascript subscribe to an account channel.
Import the library
<script src="https://js.pusher.com/8.0/pusher.min.js"></script>
Subscribe:
var pusher = new Pusher('{{PUSHER_KEY}}', {
cluster: 'mt1',
broadcaster: 'pusher',
channelAuthorization: {
endpoint: '{{API_ENDPOINT}}auth/pusher',//to endpoint created above
forceTLS: false,
encrypted: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer {{BEARER_TOKEN}}'
}
},
});
var channel = pusher.subscribe('private-account.{{ACCOUNT_UUID}}');
channel.bind('message-received', function (data) {//needs to be the same as the broadcast as
console.log('data')
console.log(data)
});
Send a message
event(new MessageReceived($conversation->account_id, $conversation->conversation_id, $request->Body));
REMEMBER: Events in Laravel are broadcast with the default queue configuration. If you have horizon installed in your application, then you need to run horizon to trigger the events.
Troubleshooting
- If the front end is not calling the authentication endpoint:
- Check that the cluster matches the application key used. For some reason it won’t throw an error, it will just fail silently and just not call the authentication endpoint.