I'm developing a website where the user can log in and make searches on different TfL data where I will send a request to the API in the backend. I am hosting my front-end on netlify and my back-end on Heroku. My problem is that when the user presses the login button, the session data shows their user id. However, then when the user is redirected to the main page I print out the session data again but there is no user id with the session.
One note is that I am redirecting the user to a different domain when they press login via ajax, then the backend authenticates them and, if successful, I send a status response of 200 back to the ajax callback and there I user window.location.href to advance the user to the main page.
I have tried all sorts of things such as cors, setting credentials to true, using mongostore, pretty much most things you can think of.
A snippet of my back-end express code
function loggedIn(req, res, next) {
console.log(req.session);
if (req.user) {
next();
} else {
res.sendStatus('501');
}
}
app.use(cookieParser());
// Express Session
app.use(session({
secret: "secret",
cookie: {
secure: true,
},
saveUninitialized: true,
resave: true,
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.getUserFromId(id, (err, user) => {
done(err, user);
});
});
app.post('/login', urlencodedParser, passport.authenticate('local', {failureRedirect: '/login-error', failureFlash: true}), (req, res) => {
req.session.save( err => {
res.send(req.user);
console.log(req.session);
});
});
app.get('/search', loggedIn, urlencodedParser, (req, res) => {
Search.find({user: req.user._id}, (err, data) => {
if(err) throw err;
res.send({searches: data});
});
});
The AJAX call that is made as soon as the user loads the main page
$.ajax({
//The type of the request is a GET request.
type: 'GET',
//We're doing a GET request to that route.
url: 'https://tfldatavis.herokuapp.com/search',
data: '',
xhrFields: {
withCredentials: true
},
//On success of the request, some data will be sent back and this function wil be fired.
success: data => {
for(let i = data.length-1; i >= 0; i--) {
$('#search-history').append('<span style="color: #2c313a">' + data.searches[i].search + '</span>');
}
},
error: (err, data) => {
if (data.status === 501) {
window.location.href = 'https://www.emreedogan.com/login';
}
}
});
The AJAX call that is made when the user presses the login button
$.ajax({
//The type of the request is a POST request.
type: 'POST',
//We're doing a POST request to that route.
url: 'https://tfldatavis.herokuapp.com/login',
//Pass along the data inside 'searchQuery' along with the request.
data: user,
xhrFields: {
withCredentials: true
},
//On success of the request, some data will be sent back and this function wil be fired.
success: data => { console.log(data); window.location.href = 'https://www.emreedogan.com/index'; },
error: (req, status, err) => {
const message = req.responseJSON.error[0];
$('#error-message').text(message);
if (message.indexOf("Email") >= 0) {
$('input[type="email"]').focus();
} else if (message.indexOf("password") >= 0) {
$('input[type="password"]').focus();
}
}
});
When the user loads the main page and makes a GET request to /search, the session data should include passport: {user: -whatever-}. However, it doesn't, it's like it doesn't save the session at all.
This is the output from the Heroku log:
The first session info output is before the user is directed to the main page. The second session info output is after the user is directed to the main page and a GET request to /search is made.
UPDATE: I fixed my problem by clearing my browser cookies in chrome. If anyone else is having this problem I recommend you try this as well! Also, if you are using AJAX to make requests to your backend, make sure you include this in your AJAX code:
xhrFields: {
withCredentials: true
}
and also if you are making cross-domain requests, make sure that your backend can accept these requests:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next();
});
I hope this helped anyone that is having trouble with this! If not, don't give up!