POST is empty during podio hook verification - hook

I'm trying to verify a hook in my Podio App.
Here's the code I'm running:
Podio::setup(PODIO_API_ID, PODIO_API_KEY);
// Turn on debugging
Podio::$debug = true;
// Authenticate the app
try {
Podio::authenticate('app', array('app_id' => PODIO_HELPDESK_APP_ID, 'app_token' => PODIO_HELPDESK_APP_TOKEN));
}
catch (PodioError $e) {
// Something went wrong. Examine $e->body['error_description'] for a description of the error.
$dbObject->logger->logDebug("podio exception: ".print_r($e,true) );
}
$dbObject->logger->logDebug("access token: ".print_r( Podio::$oauth->access_token,true)); // Your access token
$dbObject->logger->logDebug("podio event POST: ".print_r($_POST,true) );
$dbObject->logger->logDebug("podio event GET: ".print_r($_GET,true) );
So the page fires when I click the "verify" button on my hooks page - I'm getting some debug info logged. The
I'm able to output an access token, but $_POST and $_GET are both empty.
What am I doing wrong?

When webhooks are not received or data is missing the problem is almost always with the URL or the receiving server's configuration. Make sure that:
The URL of your script matches the URL you registered the webhooks with exactly. Pay special attention to for example the www subdomain or trailing slashes that could result in redirects where your server could drop the payload
Any kind of firewall on your end that strips the POST data

Related

Why res.render doesn't work after res.redirect? [duplicate]

I am building a shopping cart application in nodejs/expressjs. I am having some issues with redirecting to the correct page after a user has signed in. I have found several articles that relate closely but all of my attempts to fix it from those given articles is not doing the trick.
access: function(req, res){
var data = JSON.parse(req.body.data);
console.log(data);
Customers.findOne({"custEmail": data.custEmail}, function(err, user){
if(err){
console.log(err);
res.send("error");
}if(!user){
console.log("user not found");
res.send("error");
}else{
console.log("user found");
bcrypt.compare(data.custPassword, user.custPassword, function(err, reponse){
if(reponse){
req.session.regenerate(function(err){
if(err){
console.log(err);
res.send("error");
}else{
req.session.success = true;
res.send("Success");
//res.redirect('/');
}
});
}else{
console.log("error");
}
});
}
});
What happens is, a user enters their login information and clicks the login button. An Ajax request sends the data to this access function. The function starts by checking to see if the user exists in the database. If it does than it continues to compare the bcrypt password, if they are equal they successfully login and if they do not equal then obviously it errors out.
The issue seems to be here: }else{
req.session.success = true;
res.send("Success");
//res.redirect('/');
}
When the user email and the password match this is hit right here. It says.. set this session to true, so the user can access pages where this session is required, and then sends a Success message back to the ajax request. This currently works perfectly fine and the res.send is sent to the front end. When I uncomment the res.redirect, the expected result of 'cannot set headers after they are set' happens. So when I comment out the res.send, the res.redirect simply ends up not working at all. No error, no breaking of anything just simply nothing.
I am curious to why this redirect here would not work? The headers are not being set anywhere else in this function and the expected result should be that the redirect would work perfectly fine. Any help is greatly appreciated. Thanks.
When you send an ajax call with either XMLHttpRequest or fetch() and get the response, the browser does not do anything to the current page in the browser based on that response. So, it doesn't matter whether you send a redirect response to the ajax call or not. The browser won't change the current page in the browser, no matter what. Ajax responses generate data for your Javascript and your Javascript must then decide what to do with it.
FYI, the browser will change the current page only when the redirect happens from a browser page request or a browser submitted form post (not Javascript submitted). Since that is not how you are logging in, you can't use a redirect to change the current browser page.
So, if you're going to use an ajax call on the client for login and you want the client to change pages after a successful Ajax login, then you probably want to send the redirect URL in the login response and have the client process it and set window.location to do the redirect on login.
For example, you could change:
res.send("Success");
to this:
res.json({status: "Success", redirect: '/'});
And, then have your client code examine the return from the ajax call and if the status is successful, it can grab the redirect property and do something like:
if (ajaxResult.status === "Success") {
window.location = ajaxResult.redirect;
}
I am curious to why this redirect here would not work? The headers are
not being set anywhere else in this function and the expected result
should be that the redirect would work perfectly fine. Any help is
greatly appreciated.
The message about headers have already been sent means that the whole response has already been sent with res.send("Success"); and you are now trying to send another response. You only get one response for a given request. Once you've done res.send("Success");, the http server object has sent the whole response and then closed off that response. You can't send more data at that point.
I ask a question a question somewhere else, and stackoverflow leads me here.
Why can't res.redirect() after res.render()
Just for people bump into same question as mine, I made a summary here.
After res.render(), the response ends. And res.redirect() will set the Header to the new url in Location, which we have already sent to client, and can't be set again.
My solution for this is to code in the client side location.href ="/", if that page receive a variable like redirectAttribute = true in html tag.

VueJS axios.get returns Error: Request failed with status code 404

I've been debugging this code for a while, without much luck:
async getEvents() {
try {
let response = await axios.get("http://localhost:8000/events/");
console.log(response);
return response.data;
} catch (error) {
console.error(error);
}
}
The complete code sample is from: https://auth0.com/blog/how-to-make-secure-http-requests-with-vue-and-express/
I receive an error when visiting the site that calls the API endpoint:
Error: Request failed with status code 404
at createAxiosError (utils.js?c786:148)
at Object.settle (utils.js?c786:127)
at handleRequest (handle_request.js?da0c:126)
at eval (index.js?94db:26)
at new Promise (<anonymous>)
at MockAdapter.eval (index.js?94db:25)
at dispatchRequest (dispatchRequest.js?5270:52)
If I just copy the url (http://localhost:8000/events/) in the browser I receive the correct data. I have tried with and without trailing slashes.
Am I misunderstanding the error message, and should I look elsewhere?
In computer network communications, the error 404 indicates that the browser was able to communicate with a given server, but the server could not find what was requested, in other words, the request url did not exist. So you want to double-check that.
Solution: Go to the network tab, click on the error request, inside the Headers, you can see the actual request url which has been sent to the server.
A 404 usually indicates that the resources was not found. Have you added any previous setup to your Axios instances? like the baseURL?
Most of the time the BaseURL is set to on an Axios instance that can cause confusion and issues.
I Had the same issue, then just added in my catch(vuex) error.response

res.redirect works on Postman but don't work in chrome [duplicate]

I am building a shopping cart application in nodejs/expressjs. I am having some issues with redirecting to the correct page after a user has signed in. I have found several articles that relate closely but all of my attempts to fix it from those given articles is not doing the trick.
access: function(req, res){
var data = JSON.parse(req.body.data);
console.log(data);
Customers.findOne({"custEmail": data.custEmail}, function(err, user){
if(err){
console.log(err);
res.send("error");
}if(!user){
console.log("user not found");
res.send("error");
}else{
console.log("user found");
bcrypt.compare(data.custPassword, user.custPassword, function(err, reponse){
if(reponse){
req.session.regenerate(function(err){
if(err){
console.log(err);
res.send("error");
}else{
req.session.success = true;
res.send("Success");
//res.redirect('/');
}
});
}else{
console.log("error");
}
});
}
});
What happens is, a user enters their login information and clicks the login button. An Ajax request sends the data to this access function. The function starts by checking to see if the user exists in the database. If it does than it continues to compare the bcrypt password, if they are equal they successfully login and if they do not equal then obviously it errors out.
The issue seems to be here: }else{
req.session.success = true;
res.send("Success");
//res.redirect('/');
}
When the user email and the password match this is hit right here. It says.. set this session to true, so the user can access pages where this session is required, and then sends a Success message back to the ajax request. This currently works perfectly fine and the res.send is sent to the front end. When I uncomment the res.redirect, the expected result of 'cannot set headers after they are set' happens. So when I comment out the res.send, the res.redirect simply ends up not working at all. No error, no breaking of anything just simply nothing.
I am curious to why this redirect here would not work? The headers are not being set anywhere else in this function and the expected result should be that the redirect would work perfectly fine. Any help is greatly appreciated. Thanks.
When you send an ajax call with either XMLHttpRequest or fetch() and get the response, the browser does not do anything to the current page in the browser based on that response. So, it doesn't matter whether you send a redirect response to the ajax call or not. The browser won't change the current page in the browser, no matter what. Ajax responses generate data for your Javascript and your Javascript must then decide what to do with it.
FYI, the browser will change the current page only when the redirect happens from a browser page request or a browser submitted form post (not Javascript submitted). Since that is not how you are logging in, you can't use a redirect to change the current browser page.
So, if you're going to use an ajax call on the client for login and you want the client to change pages after a successful Ajax login, then you probably want to send the redirect URL in the login response and have the client process it and set window.location to do the redirect on login.
For example, you could change:
res.send("Success");
to this:
res.json({status: "Success", redirect: '/'});
And, then have your client code examine the return from the ajax call and if the status is successful, it can grab the redirect property and do something like:
if (ajaxResult.status === "Success") {
window.location = ajaxResult.redirect;
}
I am curious to why this redirect here would not work? The headers are
not being set anywhere else in this function and the expected result
should be that the redirect would work perfectly fine. Any help is
greatly appreciated.
The message about headers have already been sent means that the whole response has already been sent with res.send("Success"); and you are now trying to send another response. You only get one response for a given request. Once you've done res.send("Success");, the http server object has sent the whole response and then closed off that response. You can't send more data at that point.
I ask a question a question somewhere else, and stackoverflow leads me here.
Why can't res.redirect() after res.render()
Just for people bump into same question as mine, I made a summary here.
After res.render(), the response ends. And res.redirect() will set the Header to the new url in Location, which we have already sent to client, and can't be set again.
My solution for this is to code in the client side location.href ="/", if that page receive a variable like redirectAttribute = true in html tag.

MongoDB Stitch double encodes redirect URI during Facebook login attempt breaking the login process?

I am trying to use the MongoDB Stitch examples tutorial for the Web based Todo App. I am using Node.JS v10.14.2 on a Ubuntu 18.04 Bionic Beaver Linux station.
When I try to log in with Facebook, the login process fails with Facebook complaining that the redirect URL generated by the Stitch server is not whitelisted, and therefore has been rejected during the attempt to login into Facebook with OAuth. The URL is generated during this code block found in this Node module:
node_modules/mongodb-stitch-browser-core/dist/cjs/core/auth/internal/StitchAuthImpl.js
Here is the code that generates the URL that starts the login process. It calls the Stitch server and the Stitch server generates the correct URL to ask Facebook to login the user. Note, I did modify the code but only to show me the value the getAuthProviderRedirectRoute() call was generating. No other changes were made.
StitchAuthImpl.prototype.loginWithRedirect = function (credential) {
var _this = this;
var _a = this.prepareRedirect(credential), redirectUrl = _a.redirectUrl, state = _a.state;
this.requestClient.getBaseURL().then(function (baseUrl) {
// ROS: We want to see the URL being created - ESM.
let replaceUrl = baseUrl +
_this.browserAuthRoutes.getAuthProviderRedirectRoute(credential, redirectUrl, state, _this.deviceInfo);
_this.jsdomWindow.location.replace(replaceUrl);
});
};
Here is the value of replaceUrl that shows the URL that was generated at this initial stage of the Facebook login process:
replaceUrl = https://stitch.mongodb.com/api/client/v2.0/app/my_stitch_app/auth/providers/oauth2-facebook/login?redirect=http://localhost:8001/&state=<<redacted>>&device=<<redacted>>
Stitch generates this URL for the start of the OAuth Facebook login handshake. As you can see from the code this URL is loaded into the browser's location. The stitch server then generates the URL for the next leg of the OAuth handshake. I have excerpted the redirect_uri query argument from the URL it generates and transfers control to, shown here:
redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
I then manually decoded the redirect URI because it looked wrong. If you look at the redirect_uri query argument shown above, you will see that the OAuth callback URI has been double encoded with the encodeUri() method. This causes the Facebook OAuth server to reject the callback URI because after being decoded, it looks like the URL shown next to the DECODED ONCE label shown below.
This causes the OAuth handshake to fail because it does not match the URL that you see below marked with the label "DECODED AGAIN".
That value is what I put in the Facebook OAuth "Client OAuth Settings" page in the "Valid OAuth Redirect URIs" section as instructed to by the MongoDB Stitch tutorial. Since the URL has been double encoded, the redirect URI when decoded once, doesn't match the "DECODED AGAIN" value and the login process fails. Obviously I could add the "DECODED ONCE" value to the whitelisted URLs list, but that would just kick the problem down the road because it should look like the completely decoded value in "DECODED AGAIN".
DECODED ONCE:
redirect_uri=https%3A%2F%2Fstitch.mongodb.com%2Fapi%2Fclient%2Fv2.0%2Fauth%2Fcallback
DECODED AGAIN:
redirect_uri=https://stitch.mongodb.com/api/client/v2.0/auth/callback
To recapitulate, when Facebook is asked to login in the user with the URL generated by Stitch, shown below, Facebook fails the process with the error message also shown below:
https://www.facebook.com/login.php?skip_api_login=1&api_key=<<redacted>>&kid_directed_site=0&app_id=<<redacted>>%26redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
Facebook Error:
URL Blocked
This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings. Make sure Client and Web OAuth Login are on and add all your app domains as Valid OAuth Redirect URIs.
I have scoured the MongoDB Stitch control panel and I don't see anywhere I may have entered something that would lead to the callback URL being passed to Facebook by Stitch, to be double-encoded. Can anyone tell me what could cause this unwanted behavior and how to fix this?
Thanks for the detailed explanation. I tried reproducing your issue but I was able to login with Facebook successfully.
I also checked the URL that the Stitch server generates when redirecting to Facebook, and it was the exact same double-encoded URI you have in your post. This means that this behavior is expected and should not affect the login flow.
If you look at the full URL, you'll see that the main url (starting at "https://www.facebook.com/login.php") has a query parameter called "next". The "next" parameter is a URL, so it needs to be URL-encoded. This URL passed to "next" has the "redirect_uri" parameter, which is also a URL, so it needs to be URL-encoded as well. Since this is a URL in a URL in a URL, this is why you see the double-encoding.
I formatted the URL with each parameter on a new line, and each sub-URL intended to help demonstrate this:
https://www.facebook.com/login.php
?skip_api_login=1
&api_key=<redacted>
&kid_directed_site=0
&app_id=<redacted>
&signed_next=1
&next=https%3A%2F%2Fwww.facebook.com%2Fdialog%2Foauth
%3Faccess_type%3Doffline
%26client_id%<redacted>
// this is the double encoded URL
%26redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
%26response_type%3Dcode
%26scope%3Demail%2Bpublic_profile
%26state%3D<redacted>
%26ret%3Dlogin
%26fallback_redirect_uri%<redacted>
&cancel_url=https%3A%2F%2Fstitch.mongodb.com%2Fapi%2Fclient%2Fv2.0%2Fauth%2Fcallback
%3Ferror%3Daccess_denied
%26error_code%3D200
%26error_description%3DPermissions%2Berror
%26error_reason%3Duser_denied
%26state%3D<redacted>
&display=page&locale=en_US
To get Facebook login working, I would ensure the following:
In the Facebook console, make sure this URL is added to the list of "Valid OAuth Redirect URIs":
https://stitch.mongodb.com/api/client/v2.0/auth/callback
In the Stitch console, make sure that your application URL is included in the list of "Redirect URIs" for the Facebook Provider. This should include any trailing slashes.
In your application code, make sure you are calling the following JS code when your redirect URL is hit. This allows the the Stitch client SDK to get the result of the OAuth2 flow performed by the Stitch server:
if (yourStitchClient.auth.hasRedirectResult()) {
return yourStitchClient.auth.handleRedirectResult().then(user => {
console.log("Authenticated as user: " + user);
});
}
Check out https://docs.mongodb.com/stitch/authentication/facebook/ for more explanation on these steps.
If you're still having trouble getting this to work after the above steps, let me know and I'll try to help you debug the issue.

Using spotify-web-api-node to generate an authentication token

I am new to using nodejs and am working on a project where I can make a custom playlist by adding one song at a time via a search. I've been able to get the code to do the searching and grabbing the proper ids done, but when trying to add to the playlist, I'm getting an error about the scope being wrong. Long story short, I was doing the wrong type of authentication.
So I read up on the spotify-web-api-node documents, but I'm getting lost between generating the authorization url and then getting the response, which is then used by another method to get the authorization token. I'm not sure if there is another method I'm not seeing that will make the request, or if I'm just supposed to do a regular request out via normal node methods.
The code I'm using is pretty much a copy-paste from the following link (https://github.com/thelinmichael/spotify-web-api-node#authorization), where the second box with the header "The below uses a hardcoded authorization code..." is where I'm lost... I need to get that code from the response, but I'm not sure how I'm to send the request to even get the response, the createAuthorizeURL method just seems to make the actual url but not send it.
I believe the confusion stems from the way the Authorization Code flow works, and the way I've written the documentation for the node wrapper. The purpose of the createAuthorizeURL method is to help you create the URL that you need to forward the user to.
From the same piece of documentation that you linked to:
In order to get permissions, you need to direct the user to our Accounts service.
Generate the URL by using the wrapper's authorization URL method.
So let's say that the user starts out by entering your site, http://www.jd.example.com. It'll have a Spotify styled button that says Login here. The button links to the URL that the createAuthorizeURL has generated. One very important part of the URL is the redirect_uri query parameter. For example, the URL that you would generate would look something like
https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&
response_type=code&redirect_uri=https://www.jd.example.com/callback&
scope=playlist-modify-public
When the user clicks the button they will be taken through the authentication and authorization flow on Spotify's site (accounts.spotify.com/). However, when they've finished this flow, they will be directed by Spotify to the same redirect_uri that you gave in the createAuthorizeURL, e.g. https://www.jd.example.com/callback.
This means that your web server (e.g. Express) needs to be able to handle a request to the redirect_uri. If your web server was indeed Express, it may look like this.
/* Some express.js setup here */
/* Some spotify-web-api-node setup here */
/* Handle authorization callback from Spotify */
app.get('/callback', function(req, res) {
/* Read query parameters */
var code = req.query.code; // Read the authorization code from the query parameters
var state = req.query.state; // (Optional) Read the state from the query parameter
/* Get the access token! */
spotifyApi.authorizationCodeGrant(code)
.then(function(data) {
console.log('The token expires in ' + data['expires_in']);
console.log('The access token is ' + data['access_token']);
console.log('The refresh token is ' + data['refresh_token']);
/* Ok. We've got the access token!
Save the access token for this user somewhere so that you can use it again.
Cookie? Local storage?
*/
/* Redirecting back to the main page! :-) */
res.redirect('/');
}, function(err) {
res.status(err.code);
res.send(err.message);
}
});
});
Hope this helps!

Resources