I'm using laravel-echo-server along with Redis and vuejs to broadcast events through websockets in Laravel 5.5. with public channels it is working fine and events get broadcasted to client-side correctly. But when I change it to private channel I face problem of authentication even if the callback function inside channel.php file just return true and does not contain any logic for authentication.
I'm using Sentinel authentication package and I don't know if this is the problem. But as I said, when just returning 'true' the problem of authentication still there.
When I check laravel-echo-server I see that there is a error message that says "could not be authenticated, got http code 419".
I read that there are some guys face same issue and what they got is maybe a csrf-token issue or private channel works only with the integrated auth package...etc.
I have included the csrf-token header inside window.Echo config but no result.
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
auth: {
headers: {
'X-CSRF-TOKEN': $('meta[name=csrf-token]).attr(content)
}
}
});
routes/channel.php
<?php
Broadcast::channel('adminNotify', function() {
return true;
});
What I did actually in order to make the admin which has the id of 1 able to receive the event is this:
<?php
use Cartalyst\Sentinel\Laravel\Facades\Sentinel;
Broadcast::channel('adminNotify', function () {
return (int) Sentinel::check()->id === 1;
});
App\Events\NotifyAdminEvent
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Ad;
use Sentinel;
class NotifyAdminEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $ad;
public function __construct(Ad $ad)
{
$this->ad = $ad;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('adminNotify');
}
}
app.js
require('./bootstrap');
window.Vue = require('vue');
import Echo from 'laravel-echo';
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
laravel-echo-server.json
{
"authHost": "http://192.168.10.11",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "64fe4c095b0ffb30",
"key": "9e2bf37f9b3c8c88c3c5f5e207754f1d"
}
],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"apiOriginAllow": {
"allowCors": false,
"allowOrigin": "",
"allowMethods": "",
"allowHeaders": ""
}
}
Laravel log does not log anything so I find it difficult to know what's going on and solve the problem.
I have figured out what happened. The problem was in laravel-echo-server.json file and exactly in the first line "authHost" where instead of putting the ip I had to put the domaine name.
{
"authHost": "http://webdev-app.test",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "64fe4c095b0ffb30",
"key": "9e2bf37f9b3c8c88c3c5f5e207754f1d"
}
],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"apiOriginAllow": {
"allowCors": false,
"allowOrigin": "",
"allowMethods": "",
"allowHeaders": ""
}
}
Related
I have this weird issue I can't fix with authenticating private channels. I am using Laravel 8, NuxtJS (SPA app), Redis, and separate Docker containers for everything.
When I am trying to listen in my SPA NuxtJs app for the private channel I get the following error:
42["subscription_error","private-robert-test-1",0]
I assume this is because of my echo confing in nuxt.config.js:
echo: {
broadcaster: 'socket.io',
host: 'http://publisher-local.co.uk:8080',
// authModule: true,
// disconnectOnLogout: true,
// token: this.token
},
Then the call looks like this(in the ws tab in my browser):
42["subscribe",{"channel":"private-robert-test-1","auth":{"headers":{}}}]
I assume it should have something in the auth object. So I followed the documentation of NuxtJS Laravel Echo Server package and tried to set authModule to true. As soon as I do that I get this weird error:
Now I imagine that if it worked then auth module would simply add a token to the subscription message I showed before (the one with an empty auth key).
In Laravel I have already done this Broadcast::routes(['middleware' => ['auth:api']]); in the BroadcastServiceProvider.
Although I don't think I am even getting there.
This is my Laravel echo server config file.
{
"apiOriginAllow": {},
"authEndpoint": "/broadcasting/auth",
"authHost": "http://publisher-local.co.uk:8080/api/v1",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {
"host": "redis",
"port": "6379",
"keyPrefix": "",
"options": {
"db": "0"
}
},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
},
"publishPresence": true
},
"devMode": false,
"host": null,
"port": 6001,
"protocol": "http",
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"socketio": {},
"subscribers": {"http": true, "redis": true}
}
Public channels on the other hand work just fine.
What am I missing here? Thank you in advance.
EDIT:
I have also tried creating a plugin for echo where I could populate information I need myself and it looks like this:
export default function ({ $echo, $auth}) {
console.log($echo.connector.options.auth)
let authData = {
headers: {
Authorization: $auth.strategy.token.get(),
Accept: 'application/json',
"X-Requested-With": 'XMLHttpRequest'
},
};
$echo.connector.options.auth = authData;
$echo.options.auth = authData;
}
So I do have the token now and other headers I can see them in the WS tab but it does not make any difference.
Probably not relevant anymore.. But if so..
You should update your version of laravel echo to v2* => https://github.com/nuxt-community/laravel-echo-module/releases/tag/v2.0.0-alpha.5
Everything works just fine with laravel redis and everything running and working with no issues. However, I am not getting a console log for my event from react native and there is no warnings or errors. Here is my code
App.js
import Echo from 'laravel-echo/dist/echo';
import Socketio from 'socket.io-client';
const echo = new Echo({
broadcaster: 'socket.io',
host: 'http://localhost:6001',
client: Socketio,
auth: {
headers: {
'Authorization': 'Bearer 7ebee00f74965d11cae413998a13c802',
},
},
});
let orderId = 9;
echo.channel('app_database_order.' + orderId)
.listen('.OrderStatusEvent', (e) => {
console.log('event: ', e);
});
and this is my Laravel echo server console
⚠ Starting server in DEV mode...
✔ Running at localhost on port 6001
✔ Channels are ready.
✔ Listening for http events...
✔ Listening for redis events...
Server ready!
Channel: app_database_order.9
Event: OrderStatusEvent
Channel: app_database_order.9
Event: OrderStatusEvent
Channel: app_database_order.9
Event: OrderStatusEvent
laravel-echo-server.json:
{
"authHost": "http://localhost",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "AppId",
"key": "7ebee00f74965d11cae413998a13c802"
}
],
"database": "redis",
"databaseConfig": {
"redis": {
"port":"6379",
"host":"127.0.0.1",
"db":"0",
"password":"0TaEotyBIzOSym6zEXdsD2f2VCiPJmj4s/2nkGgyC4BBnm7CVUphOPCJ3LYoEUWuuqLokqJ/CCrJ3HqR"
},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
},
"publishPresence": true
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"secureOptions": 67108864,
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": true,
"allowOrigin": "*",
"allowMethods": "GET, POST",
"allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
}
}
And I am trying to trigger the event by calling this API from postman:
Route::post('/ship', function (Request $request)
{
$order_id = $request->input('order_id');
$order = Order::findOrFail($order_id);
event(new OrderStatus($order));
return true;
});
Order Status Event:
class OrderStatus implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $order_id;
public function __construct(Order $order)
{
$this->order_id = $order->id;
}
public function broadcastOn()
{
return new Channel('order.'.$this->order_id);
}
public function broadcastAs() {
return 'OrderStatusEvent';
}
}
I am using expo to run react-native, so the log should appear in the expo console,
and nothing appears.
I am working on this problem for 3 days with no solutions :(.
Please help.
Try downgrading to Echo version 2.4.0. It solved the problem for me.
Also, in place of echo.listen() use echo.on()
I am building a SPA. I am using laravel for backend and vuejs for front end. They are running independently on different port. (Using laravel api)
Laravel is running on 8000
Vue is running on 8082
I am allowing user to authenticate using JWT Auth.
I am trying to make a real time data transfer application using laravel-echo-server and have used public channel to transfer data and this worked great.
Now I need to use private channel to broadcast data to authenticated user and that's where I am not able to figure out how to make it work and I am getting error such as
NuG9yhe46E3N9Q6zAAAA could not be authenticated to private-some-p
rivate-channel
Client can not be authenticated, got HTTP status 403
here is laravel-echo-server.json file
{
"authHost": "http://localhost:8000",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "mprimeapp",
"key": "d8f6639653d0c4f31efa56d27f6ab502"
}
],
"database": "redis",
"databaseConfig": {
"redis": {
"port": "6379",
"host": "127.0.0.1"
},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": "localhost",
"port": "8890",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"apiOriginAllow": {
"allowCors": true,
"allowOrigin": ["http://localhost:8000", "http://localhost:8082"],
"allowMethods": "GET, POST",
"allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
}
}
I am using redis not sqlite database that is running also.
My main.js file vue app
const tokenData = JSON.parse(window.localStorage.getItem('authUser'))
if (tokenData !== null) {
window.Echo = new Echo({
broadcaster: 'socket.io',
host: 'http://localhost:8890',
auth: {
headers: {
'Authorization': 'Bearer ' + tokenData.token
}
}
})
}
window.Echo.private('some-private-channel')
.listen('SomeEvent', (e) => {
console.log(e)
})
here are feew things that i wanted to ask.
authEndpoint in laravel-echo-server.json file, how does it work? do i have to make an end point in my api.php file to authenticate user.
clients array in laravel-echo-server.json file, what is use of data inside it?
In Laravel app inside config/app.php
I have this line uncommented App\Providers\BroadcastServiceProvider::class
In BroadcastServiceProvider.php
public function boot()
{
Broadcast::routes([ 'middleware' => [ 'auth:jwt.auth' ] ] ]);
require base_path('routes/channels.php');
}
UPDATE
It seems like there is something wrong with above function. To be more specific thing thing [ 'middleware' => [ 'api', 'jwt.auth' ] ]
Getting this error after changing middlware array
[15:58:13] - vAKK8BO7vs2TZy4SAAAA could not be authenticated to private-some-private-channel
{
"message": "Auth guard [jwt.auth] is not defined.",
"exception": "InvalidArgumentException",
"file": "C:\\xampp\\htdocs\\mipm-l\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\AuthManag
er.php",
.....
.....
.....
Have you installed and configured a JWT Auth package https://github.com/tymondesigns/jwt-auth ? (Sorry but you did not mention)
Also make sure you have following lines in your Kernel.php
protected $routeMiddleware = [
...
'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
...
];
I tried a lot but still can not setup properly LaravelEcho. Actually i unable to setup authentication step.The private channel are not authenticating. here is larave-echo CLI result
Boostrap.js
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
import Echo from "laravel-echo"
// window.Pusher = require('pusher-js');
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: 'http://localhost:6001'
});
Layout.blade.php
Echo.private('App.User.'+id)
.notification((notification) => {
console.log(notification);
});
laravel-echo-server.json
{
"authHost": "http://bigplan.com",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "*********",
"key": "*************************"
}
],
"database": "redis",
"databaseConfig": {
"redis": {
"port": "6379",
"host": "localhost"
},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": false,
"host": "localhost",
"port": "6001",
"protocol": "http",
"referrers": [],
"sslCertPath": "",
"sslKeyPath": "",
"verifyAuthPath": true,
"verifyAuthServer": false
}
You might be missing the routes to authenticate, by default it's located in routes/channel.php. The broadcast callback should return true if it's authenticated.
Here is an example :
Broadcast::channel('notify.{employeeId}', function ($user, $employeeId) {
$employee = $user->employee;
if (!$employee){
return false;
}
return $employee->id==$employeeId;
});
notify.{employeeId} is your private channel name that you have defined in your Event class/
$employeeId here is the one that you send from echo client, it can be anything, in my case, it's employee ID.
$user is the current authenticated user.
Docs:
https://laravel.com/docs/5.5/broadcasting#authorizing-channels
I am working on making a real-time notifications with Laravel-Redis-Socketio-LaravelEcho. So far, i am able to broadcast to pubic channel but stuck with private channel.
My bootstrap.js:
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
Laravel-echo-server.json:
"authHost": "http://localhost",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "{{Omitted purposely}}",
"key": "{{Omitted purposely}}"
}
],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": ""
In my notification class, i have broadcastOn() as:
public function broadcastOn() {
return new PrivateChannel('my-channel');
}
And my-client side is:
Echo.private('my-channel')
.notification((notification) => {
console.log('I am here');
});
Everything is working fine with Public Channel but With Private Channel, command line shows the following after starting laravel-echo-server :
Error: Connect ECONNREFUSED 127.0.0.1:80.
Error sending authentication request.
You have to add broadcast authentication routes by uncommenting the below line in config/app.php
App\Providers\BroadcastServiceProvider::class,
so that in your routes/channel.php will check for particular guard and return 1 or 0 depending on your conditions