Reputation: 509
I have recently delved into Laravel 5.3's Laravel-Echo and Pusher combination. I have successfully set up public channels and moved on to private ones. I am having trouble with Laravel returning a 403 from the /broadcasting/auth route, no matter what I do to try to authorize the action (up to and including using a simple return true statement). Can anyone tell me what I am doing wrong?
App/Providers/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();
/*
* Authenticate the user's personal channel...
*/
Broadcast::channel('App.User.*', function ($user, $userId) {
return true;
});
}
}
resources/assets/js/booststrap.js:
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'My-Key-Here'
});
window.Echo.private('App.User.1')
.notification((notification) => {
console.log(notification.type);
});
I can see the event and it's payload in my Pusher debug console, it is simply failing once it hits the auth route.
Upvotes: 36
Views: 50471
Reputation: 1
Adding
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
to /config/auth.php, as suggested by @Marianela Diaz, made my code work.
Upvotes: 0
Reputation: 61
For those using Laravel 11, the BroadcastServiceProvider
class isn't available anymore. In my case, adding the appropriate broadcast config in the routes/channels.php
file worked.
I am using Laravel 11 and Sanctum, and this is the content of the routes/channels.php
file:
use Illuminate\Support\Facades\Broadcast;
Broadcast::routes(['middleware' => 'auth:sanctum']);
Upvotes: 1
Reputation: 14994
For me, the 403 error was caused by empty channel_name for JWT refresh. For some reason Axios sends Content-Type: text/plain;charset=UTF-8
which resulted in empty $request->channel_name
. I set the header explicitly
window.Pusher = require('pusher-js/with-encryption');
window.Echo = new Echo({
broadcaster: 'pusher',
key: key,
host: host,
cluster: 'us3',
forceTLS: true,
authorizer: (channel) => {
return {
authorize: (socketId, callback) => {
//HERE header needed
const options = { headers: { 'Content-Type': 'application/json' } };
const data = {
socket_id: socketId,
channel_name: channel.name,
};
apiChatAxios
.post(`/broadcasting/auth`, data, options)
.then((response) => {
callback(false, response.data);
})
.catch((error) => {
callback(true, error);
});
},
};
},
});
``
Upvotes: 0
Reputation: 99
When you try to set up private channels in my case I use JWTTokens in laravel. For doing that in /config/auth.php you need to establish the guard that we will use to get the authenticated user
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
In the last piece of code we put for api guard we get the authenticated user from JWT.
In BroadcastServiceProvider we define the routes
class BroadcastServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::routes();
require base_path('routes/channels.php');
}}
In routes/channels.php we establish the route for the private channel and WE MUST ADD THE GUARD OPTION in the declaration of the route
Broadcast::channel('fileszipped.{id}', function ($user, $id) {
return $user->id == $id;}, ['guards' => ['api']]);
Then in the event, that we use to broadcast the message we declare that we broadcast the message over the channel declared. You should pass in the constructor of this event, the authenticated user:
class FileZipped implements ShouldBroadcast {
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* The file instance.
*
* @var FilesUser
*/
public $fileUser;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($fileUser)
{
$this->fileUser = $fileUser;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('fileszipped.'.$this->fileUser->user->id);
}}
Finally, in the front, I used React v17 I declare this
const options = {
broadcaster: "pusher",
key: "123456_key",
cluster: "mt1",
forceTLS: false,
encrypted: false,
wsHost: '127.0.0.1',
wsPort: 6001,
//authEndpoint is your apiUrl + /broadcasting/auth
authEndpoint: "http://localhost:8000/broadcasting/auth",
// As I'm using JWT tokens, I need to manually set up the headers.
auth: {
headers: {
Authorization: "Bearer " + auth.accessToken,
Accept: "application/json"
}
}
};
const echo = new Echo(options);
useEffect(() => {
echo.private(`fileszipped.`+ auth.id)
.listen('FileZipped', (e) => {
console.log(e.fileUser.name);
setMessage(e.fileUser.name + ' is ready for download!!');
getAllFilesUser()
});
}, [])
By doing this you will receive your notifications in the front using private channels. Enjoy it!!
Upvotes: 0
Reputation: 4266
Error 403 /broadcasting/auth with Laravel version > 5.3 & Pusher, you need to change your code in resources/assets/js/bootstrap.js with
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your key',
cluster: 'your cluster',
encrypted: true,
auth: {
headers: {
Authorization: 'Bearer ' + YourTokenLogin
},
},
});
And in app/Providers/BroadcastServiceProvider.php, replace
Broadcast::routes()
with
Broadcast::routes(['middleware' => ['auth:api']]);
or
Broadcast::routes(['middleware' => ['jwt.auth']]); //if you use JWT
or
Broadcast::routes(['middleware' => ['auth:sanctum']]); //if you use Laravel
it worked for me, and I hope it helps you.
Upvotes: 45
Reputation: 159
I am facing the same Error
/broadcasting/auth 403 (Forbidden)
I just Notice that my Project/routes/channels contain
Broadcast::channel('App.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
But my User Model is placed in Project/app/Models/User.php
so I change Project/routes/channels.php to
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
/broadcasting/auth 403 (Forbidden) is fixed
also if your base url is different from http://localhost/broadcasting/auth you can define authEndpoint in Echo initialization
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true,
authEndpoint : `http://localhost/project/public/broadcasting/auth`,
});
also make sure that this piece of code is uncomment in project/config/app.php
App\Providers\BroadcastServiceProvider::class
and to listen a Private Channel Event you have to Define Echo like this in Javascript
Echo.private(`App.Models.User.{{ Auth::user()->id }}`)
.listen(".Illuminate\\Notifications\\Events\\BroadcastNotificationCreated",(notification) => {
console.log('Got event...');
});
Your project\app\Notifications\SendNotification.php Should Look Like this
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\BroadcastMessage;
class SendNotification extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['broadcast'];
}
public function toBroadcast($notifiable)
{
return new BroadcastMessage([
'message' => 'Hola!'
]);
}
}
also use Notifiable in your User Model.
In Your Controller you can call like this
$user->notify(new SendNotification());
you can debug on Pusher Dashboard Debug console below is the screenshot if I subscribe successfully.
You can test Event using Pusher Debug Console below is the screenshot
hope this will help
Upvotes: 1
Reputation: 19
-- reinstalling websockets
-- php artisan optimize:clear
Upvotes: -6
Reputation: 31
In case, someone comes in the latest Laravel 5.7 with the same issues, the good solution worked for me is to check authentication in each channel before returning or on the return like below.
Broadcast::channel('user.*', function ($user) {
return Auth::check();
});
Broadcast::channel('conversation.{id}', function ($user, $conversationId) {
Auth::check();
return $user->isInConversation(Conversation::find($conversationId));
});
This way it works with any channel broadcasting any event including users.
I hope it may help someone else.
Upvotes: 0
Reputation: 616
I paired socket.io with redis and also had a problem with 403 error, even though there weren't any authentication middlewares over /broadcasting/auth route. Only after whatching laracasts lesson I figured out that just channel authorization is not enough, there always should be user and no matter how you authenticate and obtain user, using default laravel auth or some token algorithm - jwt or anything else.
Authenticated user is automatically resolved and passed as first parameter to to closures functions in routes/channels.php file, so you can check channel availability for currently logged in user
Upvotes: 8
Reputation: 75
Check how you are authorising your channel. Depending on your setup this might help. Update your BroadcastServiceProvider with the following:
<?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(['middleware' => ['auth:api']]);
require base_path('routes/channels.php');
}
}
Adds in the Auth API middleware for use with Laravel Passport.
Upvotes: 4
Reputation: 1
This can happen if you are no longer logged in. Make sure you are actually logged into the Laravel app and that your current session hasn't expired.
I logged back in and it worked for me.
Upvotes: 0
Reputation: 21891
In my case the problem was a wrong user id:
Echo.private('user.'+CURRENT_USER_ID_HERE)
Upvotes: 2
Reputation: 4575
I solve it by creating channel route.
Create your Authorizing Channels in routes->channels.php
Broadcast::channel('chatroom', function ($user) {
return $user;
});
See Documentation : https://laravel.com/docs/5.4/broadcasting#authorizing-channels
thanks
Upvotes: 15
Reputation: 83
What worked for me was to use the method private of the Laravel Echo package: https://laravel.com/docs/5.3/notifications#listening-for-notifications
Echo.private('App.User.1')
.notification((notification) => {
console.log(notification.type);
});
Upvotes: 4