Search code examples
node.jsexpresspassport.jspassport-local

passport-local session remains empty for REST calls


I have some trouble getting passport-local to work correctly. I have a small website using React and React-Router v4. I can login ok, and stay logged in on reload. All my REST calls to the admin section result in a login screen being returned.

I want to have only certain REST calls authenticated (namely /admin*), but these REST calls all return a '/login' page.

Alright, the code:

import express from 'express';
import compression from 'compression';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import passport from 'passport';
import session from 'express-session';
import { Strategy as LocalStrategy } from 'passport-local';

const secret = 'foo';

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(cookieParser(secret));
app.use(
session({
  secret,
  saveUninitialized: false,
  resave: false,
  maxAge: null,
  cookie: {
    path: '/admin',
    secure: process.env.NODE_ENV === 'production',
  },
}),
);
app.use(passport.initialize());
app.use(passport.session());

passport.use(new LocalStrategy((email, password, done) =>
  User.findOne({ where: { email } })
    .then((user) => {
      if (!user) return done(null, false, { message: `There is no record of the email ${email}.` });

      return user.comparePassword(password).then((result) => {
        if (result) done(null, user);
        else done(null, false, { message: 'Your email/password combination is incorrect.' });
      });
    })
    .catch((err) => {
      console.log(err);
      done(null, false, { message: 'Something went wrong trying to authenticate' });
    })));

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

passport.deserializeUser((id, done) => {
  console.log('find by id', id);
  User.findById(id)
    .then((user) => {
      done(null, user.get());
    })
    .catch(done);
});

app.use(...cspSecurity);

app.use(compression());

//sequelize connect
connect();

Routes

app.post('/admin/logout', userController.logout);
app.post('/admin/login', userController.login);
app.get('/admin/rest/*', (req, res, next) {
  console.log('authenticated', req.isAuthenticated());

  if (req.isAuthenticated()) {
    next();
  } else {
    res.redirect('/login');
  }
});

app.get('/admin/rest/user', userController.all);
app.post('/admin/rest/user', userController.add);
app.put('/admin/rest/user/:id', userController.update);

Cookie returned from login:

set-cookie:connect.sid=s%3AUtm0CymuTprJHwJb_XVFscXb73-p-F0m.BIZ4R7gCy%2BHkSc%2FbC423FG71mWLxgdsdfsdMkjDRhIe8w; Path=/admin; HttpOnly

Based on a suggestion I saw, I tried adding this to my REST calls, to no avail:

const res = await fetch(`/admin/rest/user/${data.id}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    credentials: 'same-origin',
    body: JSON.stringify(data),
});

Any suggestions?


Solution

  • This had to do with a non secure connection between CloudFlare and my server and the server setting a secure cookie