React App with Express Backend & express-session

drewpel picture drewpel · Dec 5, 2017 · Viewed 8.9k times · Source

I currently have a React App (via create-react-app) and an Express server for my API calls. They are both running separately and have been working fine until I ran into this problem:

I'm also using express-session and passport for user authentication. I'm able to authenticate users but the session doesn't persist between API calls. If I successfully login, the next time I make an API call, req.sessionID will be different, and req.isAuthenticated() will return false.

Here is my server code:

'use strict'

var express         = require('express');
var path                = require('path');
var bodyParser      = require('body-parser');
var cookieParser    = require('cookie-parser');
var mongoose      = require('mongoose');
var passport      = require('passport');
var session       = require('express-session');
var cors          = require('cors');
var flash         = require('connect-flash');

var store         = require('./store');
var database      = require('./database');

var app     = express();
var port    = process.env.port || 3001;
var router  = express.Router();

var promise = mongoose.connect('mongodb://localhost:27017/lifeless-db', {useMongoClient: true});

//app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser('lifeless-secret-01890'));
app.use(session({
  secret: 'lifeless-secret-01890',
  saveUninitialized: true,
  cookie: {
    secure: false,
  }
}));
app.use(flash());

app.use(passport.initialize());
app.use(passport.session());
// Initialize Passport
var authinit = require('./auth/init');
authinit(passport);

// For debugging:
app.use(function(req, res, next) {
  console.log("SessionID: " + req.sessionID);
  console.log(req.isAuthenticated() ? "This user is logged in" : "This user is NOT logged in");
  next();
});



// GET

app.get('/items', function(req, res) {
  store.getAllItems((items) => {
    if(!items) return res.send({error: true, message: 'Error loading store :/', items: null});
    else return res.send({error: false, message: 'Success', items: items});
  });
});

app.get('/login', function(req, res) {
  console.log(req.flash());
  console.log("Login fail");
  res.send({error: true, message: 'Unknown error'});
});


// POST

app.post('/message', function(req, res) {
  database.submitMessage(req.body.email, req.body.message, (success) => {
    if (success) return res.send({error: false, message: 'Success'});
    else return res.send({error: true, message: 'Error sending message'});
  });
});


app.post('/login', passport.authenticate('local', {failureRedirect: '/login', failureFlash: true}), function(req, res) {
  console.log(req.flash());
  console.log("Login success");
  return res.send({error: false, message: 'Success'});
});



// SERVER

app.listen(port, function(){
  console.log('Server started.');
  console.log('Listening on port ' + port);
});

And here is an example of an API call from the React App (using axios):

login(e) {
    e.preventDefault();

    axios({
      method: 'post',
      url: 'http://localhost:3001/login',
      data: {
        username: this.state.username,
        password: this.state.password,
      }
    })
    .then((response) => {
      console.log(response.data);
      if (response.data.error) {
        this.setState({error: true, errmessage: response.data.message});
      } else {
        this.setState({redirect: true});
      }
    })
    .catch((error) => {
      this.setState({error: true, errmessage: 'Error logging in'});
    });
  }

I figure there must be some way to have React store the session somehow (?) but I'm fairly new to React and don't really know how to use it with an express backend.

Answer

M312V picture M312V · Aug 20, 2020

Your axios request from your React client needs to be sent withCredentials. To fix it, either do axios.defaults.withCredentials = true; or do axios.get('url', {withCredentials: true})...Also in your expressjs backend, set cors options credentials: true