Laravel echo, pusher not authenticating on private channel - laravel

I'm trying to set up a private pusher channel with echo on laravel 6. It won't authorise the user. The best I can do is get the following response from pusher
Pusher : No callbacks on private-App.User.1 for pusher:subscription_error
I've followed the documentation, I've registered:
App\Providers\BroadcastServiceProvider
added the csrf token:
<meta name="csrf-token" content="{{ csrf_token() }}">
adjusted the broadcast routes in the broadcastServiceProvider
Broadcast::routes(["middleware" => ["auth:api"]]);
Required the channels file
require base_path('routes/channels.php');
Here's the channel code, (the log isn't even running)
Broadcast::channel('App.User.{id}', function ($user, $id) {
Log::info('User failed to auth.');
return (int) $user->id === (int) $id;
});
Here's the bootstrap.js code, obviously using my genuine key and endpoint (tried with and without the endpoint)
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'mykeyhere111',
cluster: 'eu',
authEndpoint: "https://mydomain.test/broadcasting/auth",
forceTLS: true
});
Pusher.logToConsole = true;
console.log(window.Echo.options);
and my vue listen method:
Echo.private(`App.User.${userId}`)
.notification( (notification) => {
console.log(notification)
})
I've also set the env file
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=akeyhere1
PUSHER_APP_KEY=akeyhere123
PUSHER_APP_SECRET=akeyhere12345
PUSHER_APP_CLUSTER=eu
I'm working on homestead with ssl, also tried on vagrant. The network response for auth is:
Request URL: https://mysite.test/broadcasting/auth
Request Method: POST
Status Code: 302
with no response data.
I've spent a couple of days trying to get this working, nothing seems to do it. Any ideas?

Related

Laravel Sanctum & broadcasting with Pusher.js (401, 419 error)

For 4 days I have been trying to connect to a private channel. Combined all the possible properties that I could find, but nothing solved the problem. A deeper understanding of the issue is needed.
I am creating an application using Laravel Sanctum, Nuxt.js, Nuxt-auth.
I need to connect to a broadcasting private channel.
At first I tried to create a connection using the #nuxtjs/laravel-echo package.
After long attempts to configure the connection, I found that the PisherConnector instance is not even created if I set the authModule: true (Public channels connect perfectly). Having discovered that this package is not actively supported and the fact that I do not have full access to connection management, I decided to abandon it.
Then I tried to set a connection using Laravel-echo and then directly through Pusher. Nothing works, I get either a 401 or 419 error.
I have a lot of questions and no answers.
When do I need to use laravel-echo-server?
When do I need to use pusher/pusher-php-server?
In which case do I need to connect to broadcasting/auth, and in which to api/broadcasting/auth? My frontend runs on api/login, but I don't want to provide external access to my API.
I added Broadcast::routes(['middleware' => ['auth: sanctum']]) to my BroadcastServiceProvider and to routes/api.php too (for testing). I'm not sure here either. Broadcast::routes(['middleware' => ['auth: api']]) may be needed or leave the default Broadcast::routes()?
What are the correct settings for configs: config/cors.php, config/broadcasting.php, config/sanctum.php, config/auth.php? What key parameters can affect request validation?
Should I pass CSRF-TOKEN to headers? I have tried in different ways.
When do I need to set the encrypted:true option?
What middleware should be present in the Kernel and what might get in the way?
If I set authEndpoint to api/broadcasting/auth I get 419 error (trying to pass csrf-token does not help). If I set authEndpoint to broadcasting/auth I get 401 error.
I do not provide examples of my code, since I tried all the options in all configs. I also tried to learn the documentation for my issue on the Laravel site, Pusher.js, looked at examples. Various examples mention some options but not others, and vice versa.
I would be glad to any advice.
I had the same issue as you. I had forgot to add the BroadCastingServiceProvider in my /config/app.php.
The app/Providers/BroadcastServiceProvider.php now looks like this:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Broadcast::routes(['middleware' => ['api', 'auth:sanctum']]);
require base_path('routes/channels.php');
}
}
I have not added Broadcast::routes to any other route file.
This is what my Laravel Echo init looks like:
new Echo({
broadcaster: 'pusher',
key: 'korvrolf',
wsHost: window.location.hostname, // I host my own web socket server atm
wsPort: 6001, // I host my own web socket server atm
forceTLS: false,
auth: {
withCredentials: true,
headers: {
'X-CSRF-TOKEN': window.Laravel.csrfToken
}
}
})
Without the CSRF-token the endpoint will return the 419 status response.
In my index.blade.php for my SPA I print out the CSRF-token:
<script>
window.Larvel = {
csrfToken: "{{ csrf_token() }}"
}
</script>
Now, the /broadcast/auth endpoint returns a 200 response.
I had the same issue with Laravel & pusher.
I have fixed using decodeURIComponent and moving BroadCast::routes(['middleware' => ['auth:sanctum']]) to routes/api.php from BroadcastServiceProvider.php
Also, add withCredentials = true.
const value = `; ${document.cookie}`
const parts = value.split(`; XSRF-TOKEN=`)
const xsrfToken = parts.pop().split(';').shift()
Pusher.Runtime.createXHR = function () {
const xhr = new XMLHttpRequest()
xhr.withCredentials = true
return xhr
}
const pusher = new Pusher(`${process.env.REACT_APP_PUSHER_APP_KEY}`,
{
cluster: 'us3',
authEndpoint: `${process.env.REACT_APP_ORIG_URL}/grooming/broadcasting/auth`,
auth: {
headers: {
Accept: 'application/json, text/plain, */*',
'X-Requested-With': 'XMLHttpRequest',
'X-XSRF-TOKEN': decodeURIComponent(xsrfToken)
}
}
})
I hope this helps a bit.

Laravel/Vuejs and Pusher Not Connecting to Private Channel on Heroku

I have a laravel/vuejs realtime application, works on my local environment but when I deploy to heroku /auth/broadcast shows unsual response,
bootstrap.js
window.axios.defaults.headers.common = {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': window.csrf_token
};
const JWTtoken = `Bearer ${localStorage.getItem('access_token')}`
import Echo from 'laravel-echo';
// import Pusher from 'pusher-js';
window.Pusher = require('pusher-js');
Pusher.logToConsole = true;
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true,
encrypted: true,
auth: {
headers: {
'Authorization' : JWTtoken,
}
}
});
In vue.js component
Echo.private(`App.User.${this.user.id}`)
.notification((notification) => {
console.log(notification.type)
});
Response from my local environment (Successful)
Pusher : : ["Event sent",{"event":"pusher:subscribe","data":{"auth":"0d5290e189b56045e99d:e2156d7e13673a1e06f0c2b8974655247a55055de1f7eb31022a1a171615cb8c","channel":"private-App.User.4"}}]
broadcasting/auth response from local environment
Error from broadcasting/auth on heroku
Pusher : : ["Error: JSON returned from auth endpoint was invalid, yet status code was 200. Data was: "]
Error pusher broadcasting/auth
Any help or suggestions. Thanks
The auth endpoint response should be a JSON string with an auth property of a value composed from the application key and the authentication signature, separated by a colon : as follows:
{
"auth": "278d425bdf160c739803:58df8b0c36d6982b82c3ecf6b4662e34fe8c25bba48f5369f135bf843651c3a4"
}
You should check what the auth endpoint is returning.
Source

Laravel Echo not subscribing to Pusher Presence Channel, not even in Pusher dashboard

I have spend many hours to solve this issue of mine, reading the doc multiple times, googling here and there: SO, Laracast, Larachat, etc, but still couldn't get Laravel Echo to subscribe to Pusher presence channel, and it doesn't show any error in console tab
Public and Private channel are working fine and smooth, users can subscribe, users can listen / trigger event(s)
Note: before creation of this post, I have search questions related to my current issue, none of them have answer
Some questions similar to mine:
https://laravelquestions.com/2020/12/15/laravel-echo-not-joining-presence-channel-in-production/
Laravel Echo + Laravel Passport auth in private / presence websockets channels
https://laravel.io/forum/facing-issues-upon-subscribing-to-presence-channel
etc..
Spec:
Laravel: 7.30.1
laravel-Echo: 1.10.0 (latest; atm)
pusher/pusher-php-server: 4.0
pusher-js: 7.0.3 (latest; atm)
In resource/js/bootstrap.js
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true,
authEndpoint: '/api/broadcasting/auth',
auth: {
headers: {
'Authorization': `Bearer ${localStorage['token']}`
}
}
});
In routes/api.php
// https://stackoverflow.com/questions/55555844/authorizing-broadcasting-channel-in-an-spa
Route::post('/broadcasting/auth', function (Request $request) {
$pusher = new Pusher\Pusher(
env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'),
env('PUSHER_APP_ID'),
[
'cluster' => env('PUSHER_APP_CLUSTER')
]
);
// This will return JSON response: {auth:"__KEY__"}, see comment below
// https://pusher.com/docs/channels/server_api/authenticating-users
$response = $pusher->socket_auth($request->request->get('channel_name'), $request->request->get('socket_id'));
return $response;
})->middleware('auth:sanctum');
In routes/channels.php
// https://laravel.com/docs/8.x/broadcasting#authorizing-presence-channels
Broadcast::channel('whatever', function ($user) {
return [
'id' => $user->id,
'name' => $user->name
];
});
In home.vue
...
...
created() {
Echo.join('whatever') // DOES NOT WORK, Even in mounted() vue lifehook, and in Pusher dashboard, it doesn't show this channel name
.here((users) => {
console.table(users)
})
}
Q: Why Laravel Echo not subscribing to Pusher presence channel? and even in Pusher, it doesn't show channel name: presence-whatever, only disconnected (after I refreshed the page) and then connected like nothing happen
Thanks in advance
1. Make sure to set the broadcast driver to .env after that do php artisan config:clear
BROADCAST_DRIVER=pusher
2. Ferify your auth.php. I have like this
3. Check your broadcasting.php this is my dev config
4. Check CORS settings I installed fruitcake/laravel-cors and this is my cors.php config
Maybe for you supports_credentials need to be true
5. Check your channels.php. I have
Make sure to set the broadcast driver to env after that do php artisan config:clear
Use window.Echo.channel('whatever') to join the channel.
Had the exact same issue and was stuck for hours.
I changed 'useTLS' to FALSE in config/broadcasting.php and magically got it working.

Laravel private channel authorization not working

I am learning pusher to use it with Laravel, I am trying to subscribe to private channel using Laravel-echo as follow:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
Pusher.logToConsole = true; //update: added this
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
var channel = window.Echo.private('roomr');
and per Laravel documentations I have to set authorization in channel.php file so in I wrote in it:
Broadcast::channel('roomr', function ($user) {
logger('hit authorize roomr');
return true;
});
please note that I used logger('hit authorize roomr'); to know if my function is being called, but, when I check the log file it is empty which means that this function is not being called.
using developer tools in google chrome I see there is a post request sent to http://127.0.0.1:8000/broadcasting/auth which return response 200, so, I do not think the authentication is the problem.
Update:
after I added Pusher.logToConsole = true; to my javascript now in chrome console I get:
Pusher : : ["JSON returned from auth endpoint was invalid, yet status
code was 200. Data was: "]
what else I can do? please help me to solve this probem
The problem was in the .env file and I solved it by setting BROADCAST_DRIVER=pusher

Pusher with Vue and Laravel API not working

I am using Vue SPA and Laravel. I have google it for hours and tried many things but I can't find a way to make it work.
In index.html I have
<meta name="csrf-token" content="{{ csrf_token() }}">
This is my subscribe method:
subscribe() {
let pusher = new Pusher('key', {
cluster: 'ap1',
encrypted: true,
authEndpoint: 'https://api_url/broadcasting/auth',
auth: {
headers: {
'X-CSRF-Token': document.head.querySelector(
'meta[name="csrf-token"]'
)
}
}
})
let channel = pusher.subscribe(
'private-user.login.' + this.user.company_id
)
channel.bind('UserLogin', data => {
console.log(data)
})
}
I am getting a 419 error saying: "expired due to inactivity. Please refresh and try again."
If you didn't noticed there I am trying to listen to a private channel.
419 means you don't pass the CSRF token verification. To solve the issue, there are some way.
You should pass the CSRF token to the Pusher instance. You can follow the instruction here https://pusher.com/docs/authenticating_users. I'll give you an example.
let pusher = new Pusher('app_key', {
cluster: 'ap1',
encrypted: true,
authEndpoint: 'https://api_url/broadcasting/auth',
auth: {
headers: {
// I assume you have meta named `csrf-token`.
'X-CSRF-Token': document.head.querySelector('meta[name="csrf-token"]')
}
}
});
Disable CSRF verification on the auth broadcasting route. But, this is not recommended, since CSRF verification here is important.
App\Http\Middleware\VerifyCsrfToken
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'broadcasting/auth'
];
Use laravel-echo, it's behind the scene use axios, you just need to pass CSRF token to the axios header.
// I assume you have meta named `csrf-token`.
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
}
hope that answer.
I found the solution I hope it can help others:
In front end:
let pusher = new Pusher('app_key', {
cluster: 'ap1',
encrypted: true,
authEndpoint: 'https://api_url/broadcasting/auth',
auth: {
headers: {
Authorization: 'Bearer ' + token_here
}
}
})
let channel = pusher.subscribe(
'private-channel.' + this.user.id
)
channel.bind('event-name', data => {
console.log(data)
})
As you can see above no need to use csrf token, instead use the jwt token.
In the backend, go to BroadcastServiceProvider and change this:
Broadcast::routes(); to Broadcast::routes(['middleware' => ['auth:api']]);

Resources