Facebook crawler seems to trigger Forbidden errors on my ExpressJS app - facebook

I've noticed that everytime I use the Facebook debugger tool or the Facebook like button (set up using Addthis) ExpressJS ends up throwing Error: Forbidden (twice in a row).
So I assume the crawler sends a request that weirds out Express, maybe something in the headers like for this issue?
Here is the header sent by Facebook crawler:
{
host: 'runningheroes.co',
accept: '*/*',
'accept-encoding': 'deflate, gzip',
range: 'bytes=0-8999',
referer: 'http://runningheroes.co/',
'user-agent': 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)',
'x-forwarded-for': '173.252.100.117',
'x-forwarded-port': '80',
'x-forwarded-proto': 'http',
connection: 'keep-alive'
}
And here is my Express config:
app.configure(function(){
app.use(express.compress());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('port', process.env.PORT || 8000);
app.use(express.favicon(__dirname + '/public/img/favicon.ico'));
app.use(express.logger('dev'));
app.use(express.bodyParser({ keepExtensions: true }));
app.use(express.methodOverride());
app.use(express.cookieParser('secret'));
app.use(express.cookieSession({ secret: 'secret', cookie: { domain: '.runningheroes.co', maxAge: 1000*60*60*24, httpOnly: true } }));
app.use(app.router);
// Error handling:
app.use(function(err, req, res, next) {
if(!err) { return next(); }
// This is were the Forbidden errors are logged
logger.error('Express.error.middleware: ' + err);
res.redirect('/error');
});
});
Any help would be much appreciated.
PS: the debugger still succeed to parse the og meta tags and the like button works as well despite the errors.

Related

Cookies not sent with cross-origin-request

After days of searching and trying, I'm here now.
I deployed the React Application in Netlify and the Node.js backend in Heroku. Everything works fine in localhost environment. But after deploying, cookies are not sent in request header.
CORS:(Backend Node.js)
app.use(cors({
origin: CORS_ORIGIN,
credentials: true,
allowedHeaders: "Content-Type,Accept,User-Agent,Accept-Language,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,cache-control"
}));
Axios:
import axios from "axios";
axios.defaults.withCredentials = true;
export default axios.create({
baseURL: process.env.REACT_APP_BACKEND + "/api",
headers: {
"Content-type": "application/json",
"Access-Control-Allow-Origin": process.env.REACT_APP_BACKEND,
},
});
Fetching Data(Mutation): apiClient is imported from above Axios.js and cookies is handled by react-cookies
apiClient.post("/auth/login",{ email: "name#mail.com", password: "pawspaws" })
.then((res) => {
setCookie("jwt", res.data.accessToken, { path: process.env.REACT_APP_PATH || "/", domain: process.env.REACT_APP_DOMAIN, maxAge: 26000, secure: true, sameSite: 'None' });
setCookie("refresh", res.data.refreshToken, { path: process.env.REACT_APP_PATH || "/", domain: process.env.REACT_APP_DOMAIN, maxAge: 2600000, secure: true, sameSite: 'None' });
setCookie("user", res.data.user, { path: process.env.REACT_APP_PATH || "/", domain: process.env.REACT_APP_DOMAIN, maxAge: 26000, secure: true, sameSite: 'None' });
}).catch((err) => console.log(err.response))
Above code sets the cookies.. and it's working.
Now, below is the request I'm sending which doesn't send the Cookies along with the request:
apiClient.get("/posts/timeline", { params: { email: "name#mail.com" } })
.then((res) => { console.log(res.data); })
.catch((err) => { console.log(err.response) });
Well, it returns unauthorized since the Cookie is not sent at all..
Ok, i found my own solution.. It was pretty easy.. It was setting up proxy
Just added line below to package.json in frontend:
"proxy":"https://random.name.herokuapp.com",
FYI, for Netlify, we need additional _redirects file in public folder.
_redirects
/api/* https://random.name.herokuapp.com/api/:splat 200
/* /index.html 200
In my case I had hardcoded my front end api calls to the herokubackend
axios.get("https://infinite-ocean-8435679.herokuapp.com/api/user")
First removed the hrokupart from the request like this
axios.get("/api/loguserin")
Then added the proxy value to the bottom of the package.json
"proxy":"https://infinite-ocean-8435679.herokuapp.com",
Next added a file called _redirects inside the react public folder.(_redirects is the file name and it has no extension such as .txt so don't add _redirects.txt )
Add the following inside _redirects file
/api/* https://infinite-ocean-8435679.herokuapp.com/api/:splat 200
/* /index.html 200
inside _redirects file formatting will be weird just add above code replacing heroku part with your backend url.
React automatically add all the files inside the public folder to its build folder once created.
deploy the site to Netlify

Axios + Ionic React + Sails: _csrf token 403 Forbidden

I am developing an API with Sails.js and an user App with Ionic-React. At page load I make an axios request to get the _csrf token. When I submit the data from a login form to sails I always get a 403 Forbidden response. I disabled csrf (config/security.js) in sails and then I could retrieve the response. I am sending the token in the header.
I am trying too to get the session cookie but its not working I think that might be why the server refuses the request.
Ionic App:
componentDidMount(this: this) {
axios.get('http://localhost:1337/api/v1/security/grant-csrf-token')
.then(response => {
const _csrf = response.data._csrf
this.setState({
form: {
...this.state.form,
_csrf: _csrf,
}})
});
}
OnSubmit:
const { emailAddress, password, _csrf } = this.state.form;
const config= {
data: {
"emailAddress": emailAddress,
"password": password,
},
headers: {
"x-csrf-token": _csrf
},
withCredentials: true,
jar:cookieJar,
};
axios.post('http://localhost:1337/api/v1/users/authenticate', null, config)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})};
On Chrome DevTools Network Response:
On Postman this same request works and I get a 200 with the user data, and the request does include the sails.sid cookie.
I do not want to disable csrf protection, that wouldn't be a solution. Is it the sails.sid cookie that I am missing?
I am using this,
axios({
method: 'post',
crossdomain: true,
url: apiFormUrl,
data: formData,
headers: {
"Content-Type": "multipart/form-data",
"Authorization": access_token
}
})
.then
and it works

Connecting Vue to Express - 404 Not Found

I'm creating a simple app to practice connecting Vue to an Express server. I have a form that I'm attempting to send to the back end, but I can't seem to get my data to the back-end.
The error I'm receiving is:
POST http://localhost:8080/login 404 (Not Found)
My best guess is that the method in my Vue can't find a matching route on my server? If so, I'm confused as I have a route for login.
In my Vue script:
const axios = require('axios');
export default {
data: function() {
return {
user: {
email: '',
password: ''
}
}
},
methods: {
sub() {
var user = {
email: this.user.email,
password: this.user.password
}
axios.post('/login', user)
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
}
On by back-end:
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, '..')));
app.post('/login', function(req, res) {
console.log("Server HIT!!!!!!!!!!!!!!!!!!!!")
})
app.get('*', function (req, res) {
return res.sendFile('../index.html');
});
app.listen(3000);
console.log('Express server listening on port 3000');
Express is running on another port than your vue application. Vue is standard http which is 8080, but express runs on 3000 with this line:
app.listen(3000);
You are sending the request to /login, which from the point of view of your frontend is http://localhost:8080, but that's not where express is available.
Basically all you have to do is send the request to http://localhost:3000/login, simple as that.
By default express do not allow cross origin request i.e CORS. You have to enable it by setting middleware. add below lines in you server file and must be before declaring any routes
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

Angular2 and ExpressJS API - Logged In Sessions Not working

Basically I have written and Angular2 frontend client that consists of a button, when you click this button it makes a very simple request to the expressJS and passportJS api using the following function:
socialLogin(){
window.location.href='http://api.example.io/auth/facebook';
console.log('social');
this.authenticationService.getProjectsMain();
}
Once that is finished everything is fine, I can visit the api url:
http://api.example.io/v1/api/me
in my browser and see my facebook data, my problem is that when I try to get this json data from the angular2 frontend service its as though the login has never happened even though I have it open in another tab and can see that there is data on the API subdomain. I am doing a get request to the api url and its getting nothing, because nothing is there. I am guessing that this is some kind of persistent cookie but I am unsure of how to put all this together.
My app.js server file
const express = require('express');
const passport = require('passport');
const Strategy = require('passport-facebook').Strategy;
const path = require('path');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const routes = require('./routes/index');
const loginfacebook = require('./routes/login-facebook');
const callbackfacebook = require('./routes/callback-facebook');
const standardLogin = require('./routes/standardlogin');
const me = require('./routes/me');
const app = express();
app.all('/*', function(req, res, next) {
// res.header("Access-Control-Allow-Origin", "*");
console.log('origin ' + req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.header("Access-Control-Allow-Origin", req.headers.origin );
res.header('Access-Control-Allow-Credentials', true);
res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-type");
next();
});
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
/*app.use(require('express-session')({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true
}));*/
app.use(require('express-session')({
secret: 'keyboard cat',
cookie: {
path: '/',
domain: '.example.io',
maxAge: 1000 * 60 * 24, // 24 hours
},
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', routes);
app.use('/auth/facebook', loginfacebook);
app.use('/callback/facebook', callbackfacebook);
app.use('/v1/api/login', standardLogin);
app.use('/v1/api/me', me);
app.listen(80);
module.exports = app;

Logout user with services not working

I am working on a mobile app which I will be deploying using Phonegap.
Now I am able to login using Drupal 7 services and I am also getting the session name and session id. But I am not able to Logout the user. When even I am doing that.. I see this issue on my chrome console: 406 (Not Acceptable:)
I tried sending headers as "Cookie" then "sessionname=sessionid" format.. but that didn't work. Can someone please suggest a way.
You need to add the CSRF token from YOUR_SITE/services/session/token, and then add it to the header in the same way you added the Cookie, something like
'X-CSRF-Token: ' + $token
And make sure it's PUT, there is a nice example here:
http://pastebin.com/N35SN7Xj
The relevant section looks like this:
$.ajax({
url: "http://your_url/endpoint/user/logout.json",
type: 'post',
dataType: 'json',
beforeSend: function (request) {
request.setRequestHeader("X-CSRF-Token", token);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to logout');
alert(JSON.stringify(jqXHR));
alert(JSON.stringify(textStatus));
alert(JSON.stringify(errorThrown));
},
success: function (data) {
alert("You have been logged out.");
}
});
This works for me.
$http({
method: 'POST',
url: drupal_instance + api_endpoint + 'user/logout',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'X-CSRF-Token': user.token
}
})
.success(function (data, status, headers, config) {
alert('Success');
})
.error(function (data, status, headers, config) {
alert('Error');
});