Laravel Echo + Pusher: request to broadcasting/auth returns login page - laravel-5.3

I updated my application from 5.2 to 5.3 to broadcast notifications with Pusher, but when pusher try to authenticate current logged in user over broadcasting/auth, I got an error:
Pusher : No callbacks on private-App.Models.Client.9 for pusher:subscription_error
in the browser console->network->xhr, I found that the request to broadcasting/auth not giving me the auth:{token} object, but returning my login page instead !!!
I think it is a problem with middleware but I can't find it.
BroadcastServiceProvider.php:
public function boot()
{
// Broadcast::routes();
Broadcast::routes(['middleware' => ['auth:client']]);
/*
* Authenticate the user's personal channel...
*/
Broadcast::channel('App.Models.Client.*', function ($user, $userId) {
return true;
});
}
app.js: after importing pusher-js & Laravel Echo
$(document).ready(function() {
// check if there's a logged in user
if(Laravel.clientId) {
window.Echo.private(`App.Models.Client.${Laravel.clientId}`)
.notification((notification) => {
console.log(notification);
addNotifications([notification], '#notifications');
});
} });
any help would be much appreciated!

With Laravel version > 5.3 & Pusher, you need add token in header request, your code in resources/assets/js/bootstrap.js
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your key',
cluster: 'your cluster',
encrypted: true,
auth: {
headers: {
Authorization: 'Bearer ' + YourTokenLogin
},
},
});
it worked for me, and hope it help you.

After a long time of pulling my hair, I finally found the cause of this issue. I was using a package for Authentication/Authorization called cartalyst/sentinel which is great except that once installed it will entirely replace the Laravel default auth behavior. So any request to broadcasting/auth is actually rejected.

Related

Contact Form 7 Recaptcha 3 headless site

I am building a wordpress headless site (frontend using Nuxt.js) and am trying to use recaptcha v3 in contact form 7 . I have already setup the integration using the built in cf7 integration.
But, the problem is contact form 7 is marking all of my emails as spam. Therefore I installed Flamingo plugin just to see the error log. Apparently the error log says reCAPTCHA response token is empty. Which makes sense because the recaptcha is setup in WordPress while since my frontend is decoupled, it doesn't get the token.
I have read about using vue-recaptcha but that means setting up a new recaptcha that is entirely separate from the recaptcha I setup in WordPress. I can't find a way to link the recaptcha for WordPress and my frontend together.
Any advice would be very much appreciated, thanks!
A post that I found similar to mine:
https://www.reddit.com/r/Wordpress/comments/o48hd1/contact_form_7_plugin_endpoint_for_recaptcha/
, but no clear answers.
I am successful in implementing recaptcha at the frontend right now but I have no idea how to make use of the recaptcha token from WordPress for the backend and frontend to work together. The recaptcha certainly cannot be only at the frontend because else people would be able to use Postman to spam my endpoint. This is how I did it:
async function verifyCaptcha() {
try {
// #ts-ignore
recaptchaToken.value = await context.$recaptcha.execute();
const response = await axios.post(
`/captcha-api/siteverify?secret=${process.env.SECRET_KEY}&response=${recaptchaToken.value}`
);
// console.log(response)
return response;
} catch (error) {
return error;
}
}
async function onSubmit(e: any) {
const recaptchaResponse = await verifyCaptcha();
// Display error message if verification was not successful
if (!recaptchaResponse.data.success) {
// #ts-ignore
context.$recaptcha.reset()
return;
}
// If verification was successful, send the message
await submit(e);
}
I have found the solution. We simply need to pass some specific recaptcha 3 responses required by contact form 7 back to contact form 7.
const token = await context.$recaptcha.execute('login')
// console.log('ReCaptcha token:', token)
const emailBody = {
"your-name" : form.name,
"email" : form.email,
"enquiry" : form.enquiry,
"message" : form.message,
//recaptcha responses to pass back to CF7
"_wpcf7_recaptcha_response" : token,
"wpcf7_recaptcha_response" : token,
"recaptcha_response" : token,
"recaptcha" : token,
"token" : token
}
const body = new FormData()
for (const field in emailBody) {
// #ts-ignore
body.append(field, emailBody[field])
}
const headers = {
'Content-Type': 'multipart/form-data',
}
const response = await axios.post('https://yourdomain.com/wp-json/contact-form-7/v1/contact-forms/{id}/feedback', body, { headers: headers})
// Use responseData to check its status to do some logic
const responseData = response.data
onMounted(async () => {
await context.$recaptcha.init()
})
onBeforeUnmount(() => {
context.$recaptcha.destroy()
})

What can I do to resolve this pusher error-JSON returned from auth endpoint was invalid, yet status code was 200?

I still have this problem after asking the same question here: JSON returned from auth endpoint was invalid, yet status code was 200 with no response. I've looked at similar questions and followed the
suggestions: setting my broadcast driver to 'pusher', uncommenting 'App/BroadcastServiceProvider' class in my app.config file, setting debug mode to false in my .env file, etc. I have also looked at pusher docs but the issue remains unresolved for me.
I have updated my previous attempt by adding '/broadcasting/auth/' auth endpoint and headers but still the same error. But I can now see a 302 redirect to the auth route then a 302 redirect to the login route then to the dashboard with a 200 response on laravel telescope, which I wasn't seeing before now. So this suggests to me that adding the auth endpoint ought to resolve the issue but it doesn't.
I also tried setting up and using a '/pusher/auth/' auth end point route and controller but it gave me a 'Failed to load resource: the server responded with a status of 405 (Method Not Allowed)' along with "Error: Unable to retrieve auth string from auth endpoint - received status: 405 from /pusher/auth, but not the previous invalid json error. I get this with a 'get' request to the controller but a 500-internal server error with a 'post' request. I really don't know which is correct.
This is my bootstrap.js file:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
// Enable pusher logging - don't include this in production
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,
authEndpoint: '/broadcasting/auth',
//authEndpoint: '/pusher/auth',
auth: {
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
}
}
});
This is one pusherController I created:
public function pusherAuth(Request $request)
{
$key = getenv('PUSHER_APP_KEY');
$secret = getenv('PUSHER_APP_SECRET');
$app_id = getenv('PUSHER_APP_ID');
$pusher = new Pusher($key, $secret, $app_id);
$auth = $pusher->socket_auth($_GET('channel_name'), $_GET('socket_id'));
return response($auth, 200);
}
I now know my vue frontend file that should receive and display the broadcast checks out and the issue has to do with resolving this pusher subscription error.
Any help will be appreciated.
Check your .env for the correct Broadcast driver:
BROADCAST_DRIVER=pusher
I was finally able to resolve this issue. The problem was entirely an authentication issue as the error messages pointed out. While I still don't know why the built in '/broadcast/auth' endpoint didn't work, my initial attempt to authenticate by creating a '/pusher/auth/' was wrong in the way I set up the route and controller.
The correct route set up should be 'post' and call a controller, using a closure based route didn't work for me. My previous (see above) implementation of the controller was also wrong.
This is the controller code that worked:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Pusher\Pusher;
class PusherController extends Controller
{
/**
* Authenticates logged-in user in the Pusher JS app
* For private channels
*/
public function pusherAuth(Request $request)
{
$user = auth()->user();
$socket_id = $request['socket_id'];
$channel_name =$request['channel_name'];
$key = getenv('PUSHER_APP_KEY');
$secret = getenv('PUSHER_APP_SECRET');
$app_id = getenv('PUSHER_APP_ID');
if ($user) {
$pusher = new Pusher($key, $secret, $app_id);
$auth = $pusher->socket_Auth($channel_name, $socket_id);
return response($auth, 200);
} else {
header('', true, 403);
echo "Forbidden";
return;
}
}
}
This is the final bootstrap.js file:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
// Enable pusher logging - don't include this in production
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,
authEndpoint: '/pusher/auth',
auth: {
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
}
}
});
And my route code in web.php:
Route::post('/pusher/auth', [PusherController::class, 'pusherAuth'])
->middleware('auth');
Pusher console log:
Pusher : : ["Event recd",{"event":"pusher_internal:subscription_succeeded","channel":"private-user.3","data":{}}]
vendor.js:41325 Pusher : : ["No callbacks on private-user.3 for pusher:subscription_succeeded"]

Angular HttpClient calls are missing query string and Authorization header

When Angular makes a GET call using HttpClient, the query parameters and Authorization header are missing on the request in our QA environment. When running Angular locally, pointed to the QA APIs, it sends them both as expected.
Here's how the query parameters are set:
const params = new HttpParams().set('schedulingOnly', schedulingOnly ? 'true' : 'false');
return this.httpClient.get<any>(this.getBaseUrl() + '/domain/getAll', { params });
Here's how the Authorization header is set (interceptor):
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (environment.useHttpMockRequestInterceptor) {
return this.useMockData(request);
} else {
request = this.AddAuthenticationHeader(request);
return next.handle(request);
}
}
private AddAuthenticationHeader(request: HttpRequest<any>) {
const request = request.clone({
headers: request.headers
.set('Authorization', 'Bearer ' + sessionStorage.getItem('access_token'))
});
return request;
}
Here's what Chrome dev tools is showing:
That's all the basic information, but below is additional information about things I've tried without success.
Is this a CORS issue? - While searching for others with this issue, I came across a lot of CORS issues. I do not believe that's the case here because Angular and the APIs are on the same domain and I can run Angular locally and hit the APIs no problem.
Do query params get sent if I hardcode them into the url? - Yes. The following worked for the query params: return this.httpClient.get(this.getBaseUrl() + '/domain/getAll?schedulingOnly=true');
Is this something wrong with the interceptor? - I don't believe so. Console.log() statements show all the expected points in code being hit. In fact, the request object after the interceptor adds the auth header shows it on there.
I also tried setting directly without the interceptor, but no luck.
const obj = {
headers: { 'Authorization': 'Bearer ' + sessionStorage.getItem('access_token') },
params: { 'schedulingOnly': schedulingOnly ? 'true' : 'false' }
};
return this.httpClient.get<any>(this.getBaseUrl() + '/domain/getAll', obj);
There are no js errors in the console except the 401 error
QA web server is IIS
APIs are ASP.NET Core
Angular is embedded within an ASP.NET Web Forms project (due to migrating that legacy code into Angular incrementally)
The issue was that PrototypeJs was interfering with Angular. This led to the issue, but no warnings or errors, so it was just silently causing this issue. PrototypeJs is used in the containing ASP.NET Web Forms app that Angular is embedded into. The reason this was working locally, but not in QA is because I actually did have functionality to not load PrototypeJs if it was an Angular page, due to noticing other issues before, but that wasn't working in QA due to the site starting on a subpath, not directly on the host, so that functionality of not loading PrototypeJs wasn't working.
Have you tried with the shorter version of adding header in your interceptor:
const request = request.clone({
setHeaders: { 'Authorization': 'Bearer ' + sessionStorage.getItem('access_token') }
});
Interceptor
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (environment.useHttpMockRequestInterceptor) {
return this.useMockData(request);
} else {
request = this.AddAuthenticationHeader(request);
return next.handle(request);
}
}
private AddAuthenticationHeader(request: HttpRequest<any>) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${sessionStorage.getItem('access_token')}`
}
});
return request;
}

Posting Comments to WordPress with WPAPI

I'm using Netlify event-triggered webhooks to call a script that's designed to post a new comment to the WordPress API. I'm trying to implement wpapi to make the POST request but not sure if I'm hooked up properly.
exports.handler = async (event, context, callback) => {
let body = JSON.parse(event.body).payload
if (body.form_name == 'comment-form') {
// I assume I have to authenticate here
var wp = new WPAPI({
endpoint: 'https://example.com/wp-json',
username: 'username',
password: '123456'
});
...
I then form the data to pass in... From what I can tell from the WordPress REST API, I can pass in a name, comment, and a post id. I'm not sure if I'm missing a parameter as I can't find any documentation about required params.
// url encode - not sure if this is required
let comment = {
author_name: encodeURI(author_name),
author_comment: encodeURI(author_name),
post: body.data.postId
}
I then try calling wp.comments().create() passing in the object and setting up a callback:
wp.comments().create(comment, function(args) {
console.log(args) }
).then(function( response ) {
console.log( response );
}).catch(function (err) {
console.log(err);
});
I am using this function in a Gatsby project and am utitlizing gatsby-source-wordpress to pull data from a WordPress site, if that makes any difference.
When I run this function in Netlify, in the function log, there is no response or error message.
Thanks

How to get Google+ profile with Meteor.loginWithGoogle?

I'm looking for a working example of Meteor.loginWithGoogle (with meteor 0.6.4.1).
I found this one for loginWithGitHub (https://www.eventedmind.com/posts/meteor-customizing-login) that works fine with GitHub.
It works fine without parameters as show here on client side :
Template.user_loggedout.events({
"click #login": function(e, tmpl){
Meteor.loginWithGoogle({
}, function (err) {
if(err) {
//error handling
alert('error : '+err.message);
} else {
}
});
}
});
with the Accounts params on server side :
Accounts.loginServiceConfiguration.remove({
service: 'google'
});
Accounts.loginServiceConfiguration.insert({
service: 'google',
clientId: 'XXXXXX',
secret: 'YYYYYY'
});
In this case how can i get currentUser information especially the mail ?
Is there a way to get the Google+ profile of the user (if he has one and allows this), the user's avatar for example ?
What are the needed parameters for requestPermissions: , what can i get with this ?
Thanks
After some research i build my own example available here : https://github.com/lc3t35/googlelogin
Thanks to :
https://github.com/m2web/githublogin
https://github.com/ananta-IO/marq
Meteor/MongoDB see available fields for publish?
https://github.com/mrtnbroder/meteor-snippets/blob/master/snippets/js/Accounts/loginWithGoogle.sublime-snippet
https://developers.google.com/accounts/docs/OAuth2Login#obtaininguserprofileinformation

Resources