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
Related
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'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": ""
}
}
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
I'm using laravel-echo with redis driver to broadcast notifications. It works perfectly on my local system. But on my server, I'm getting ERR_CONNECTION_TIMED_OUT error. Browser console displays http://ex.example.com:6001/socket.io/socket.io.js net::ERR_CONNECTION_TIMED_OUT.
I have not any knowledge about socket and redis. So I just have followed instruction of laravel official doc and laravel-echo-server. and made just one change from here. But with help of that change, I'm able to let execute remaining js script. Issue of socket.io.js is still unsolved (Also in github).
Here is steps which I have followed.
Follow Laravel Official Doc
Install Redis-Server
Install laravel-echo-server
Install socket.io-clent in my project
js
import Echo from "laravel-echo"
window.io = require('socket.io-client'); //suggested in github issue
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
laravel-echo-server.json
{
"authHost": "http://ex.example.com",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "edbf10287972d875",
"key": "96403c9f93e1a2d86185e2d21aa0fae1"
}
],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": ""
}
If anyone knows the solution, it will be appreciated.
This may sound simple, but did you check the firewall settings on your server?
edit: thanks to #AkshayVaghasiya for sharing the instructions for setting up your firewall correctly [read here].