james gill
james gill

Reputation: 61

node.js - Passport not persisting across browser requests, works with Postman

I am currently using the create-react-app boiler plate and have been attempting to add auth. I am using axios as my promise based HTTP libray with React.js. I have been using node with express, express-session, passport and passport-local on the backend.

Here is my server.js file with some exlusions:

const express = require('express');
const mysql = require('mysql');
const app = express();
const cors = require('cors');
const session = require('express-session');
const passport = require('passport');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const LocalStrategy = require('passport-local').Strategy;

// Express only serves static assets in production
if (process.env.NODE_ENV === 'production') {
  app.use(express.static('client/build'));
}

app.set('port', (process.env.PORT || 3001));

app.use(cors({
  credentials: true,
  origin: 'http://localhost:3000'
}));
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({
  secret: 'topsecretpassword',
  resave: true,
  saveUninitialized: false,
  cookie: {
    path: '/',
    originalMaxAge: 1000 * 60 * 60 * 24,
    httpOnly: true,
    secure: false
  }
}));
app.use(passport.initialize());
app.use(passport.session());


// Setup Database connection
const connection = mysql.createConnection({
  host : 'localhost',
  user : 'root',
  password : '',
  database : 'mvy_db'
});

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(user, done) {
  connection.query('SELECT * FROM users WHERE id=?', user, function(err, userId) {
    if (err) {
      res.status(400).json({
        error: 'Database Error',
        id: userId[0]
      });
    }

    done(err, userId[0]);
  });
});

passport.use(new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  },
  function(email, password, done) {
    connection.query('SELECT * FROM users WHERE email=?', email, function(err, user) {
      if (err) {
        return done(err);
      }
      if (!user.length) {
        return done(null, false, { message: 'Incorrect email.' });
      }
      if (user[0].password !== password) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user[0]);
    });
  }
));

app.post('/signin', passport.authenticate('local'), function(req, res) {
  console.log(req.session);
  return res.send('login success!');
});

function isAuthenticated (req,res,next){
  console.log(req.session);
  if(req.session.passport.user)
     return next();
  else
     return res.status(401).json({
       error: 'User not authenticated'
     })

}

app.get('/checkauth', isAuthenticated, function(req,res) {
  res.status(200).json({
    status: 'User Authenticated!'
  });
})

app.get('/signout', function(req,res) {
  req.session.destroy();
  res.status(200).json({ success: 'successfully signed out' });
})

Using postman (and even on the browser), I am able to successfully login and the following is held in the req.session object :

   cookie:
    { path: '/',
      _expires: null,
      originalMaxAge: 86400000,
      httpOnly: true,
      secure: false },
      passport: { user: 1 } }

my login request using axios:

return axios.post(ROOT_URL + 'signin', {
      email: e.target.email.value,
      password: e.target.password.value
    }).then((response) => {
      if (response.status === 200) {
        console.log(response);
      }
    })

My checkAuth request using axios (this is where I get a 500 error returned):

  axios.get(ROOT_URL + 'checkauth', { withCredentials: true })
    .then((response) => {
      if (response.status === 200) {
        return true;
      } else {
        return false;
      }
    });

The req.session object after checking authentication before the error message, note that the passport object doesn't exist anymore:

 Session {
   cookie:
    { path: '/',
      _expires: null,
      originalMaxAge: 86400000,
      httpOnly: true,
      secure: false } }

This is the error message I get on the console when I attempt to check that the user is authorized:

 TypeError: Cannot read property 'user' of undefined
     at isAuthenticated (/server.js:94:26)

I've been banging my head for hours, trying to resolve this issue. I thought it might have something to do with CORS, but after hours of playing around with it that doesn't seem to be the case. It's still plausible that it's a CORS issue, but what's really flustering me is that it works full well with Postman but not on my Chrome browser. Any help is appreciated!

Upvotes: 2

Views: 1566

Answers (2)

Эд Лесничий
Эд Лесничий

Reputation: 11

Oh because I forgot that axious doesn’t send credentials by default I had to stick with jwt and completely removed session.

You can define an instance of axious which will allow you to make requests much more simply

const $axios = axios.create({
  baseURL: 'https://some-domain.com/api/',
  withCredentials: true
});

Upvotes: 0

james gill
james gill

Reputation: 61

Alright, so I found the solution to my problem. It appeared to be an issue with axios and the configuration of my get requests. For some reason, using the structure axios.get(URL) .then(response) doesn't work with the withCredentials property.

Instead, I had to send my request as:

axios(ROOT_URL + 'checkauth', { method: 'get', withCredentials: true }) .then((response) => { if (response.status === 200) { return true; } else { return false; } });

Upvotes: 2

Related Questions