I've been searching for a solution because req.isAuthenticated()
always return false even after successful login.
These are the packages that I'm using:
"express": "~4.16.1"
"express-session": "^1.17.1"
"mongoose": "^5.11.5"
"passport": "^0.4.1"
"passport-local": "^1.0.0"
"connect-mongo": "^3.2.0"
I'm using connect-mongo
to store session data in MongoDB
I've referred to similar problems here like this passports-req-isauthenticated-always-returning-false-even-when-i-hardcode-done
I've tried all the possible solution, still no luck.
My passport config looks like this: I'm not sure if this is because of my serialization/deserialization
config/passport.js
const LocalStrategy = require('passport-local').Strategy;
const User = require('../schemas/UserSchema');
module.exports = function (passport) {
// used to serialize the user for the session
passport.serializeUser(function (user, done) {
done(null, user._id); // I tried user.id still doesn't work since document ids in mongodb starts with "_id" ?
});
// used to deserialize the user
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
if (err) {
return done(err);
}
done(err, user);
});
});
passport.use(
'local-login',
new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, async (req, email, password, done) => {
try {
const user = await User.findOne({ email });
if (user) {
user.passwordMatch(password, function (err, match) {
if (err) {
return done();
}
if (match) {
return done(null, user);
} else {
return done(null, false, {
error: 'Incorrect credentials.'
});
}
});
} else {
return done(null, false, { error: 'Incorrect credentials.' });
}
} catch (err) {
return done(err);
}
})
);
};
auth routes
authRoute.js
router.post(
'/v1/authenticate',
validateBody(schemas.loginSchema),
(req, res, next) => {
passport.authenticate('local-login', (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
return res
.status(401)
.send(makeErrorJson({ type: INCORRECT_CREDENTIALS, status_code: 401, message: info.error }));
} else {
console.log('LOGIN SUCCESS, IS AUTH: ', req.isAuthenticated()) // WHY IS IT FALSE?
const userData = sessionizeUser(user);
return res.status(200).send(userData); // I'M ABLE TO GET DATA IN POSTMAN
}
})(req, res, next);
});
router.get('/v1/check-session', (req, res) => {
console.log('IS AUTH:', req.isAuthenticated()) // STILL FALSE
if (req.isAuthenticated()) {
const user = sessionizeUser(req.user);
res.status(200).send(makeResponseJson(user));
} else {
res.sendStatus(404);
}
});
app.js
const createError = require('http-errors');
const express = require('express');
require('./db/db');
const path = require('path');
const session = require('express-session');
const mongoose = require('mongoose');
const logger = require('morgan');
const cors = require('cors');
const helmet = require('helmet');
const hpp = require('hpp');
const csurf = require('csurf');
const passport = require('passport');
const MongoStore = require('connect-mongo')(session);
const app = express();
const authRouter = require('./routes/api/v1/auth');
app.disable('x-powered-by');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(helmet());
app.use(hpp());
const sessionOptions = {
key: process.env.SESSION_NAME,
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
expires: 14 * 24 * 60 * 60 * 1000,
secure: false,
}, //14 days expiration
store: new MongoStore({
mongooseConnection: mongoose.connection,
collection: 'session'
})
};
console.log('NODE_ENV =', process.env.NODE_ENV);
if (process.env.NODE_ENV === 'production') {
app.set('trust proxy', 1); // trust first proxy
sessionOptions.cookie.secure = true // serve secure cookies
sessionOptions.cookie.httpOnly = true // serve secure cookies
}
app.use(session(sessionOptions));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/api', authRouter);
app.use(csurf());
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('server-error', { title: 'Server Error' });
});
require('./config/passport')(passport);
module.exports = app;
After testing login in POSTMAN
, user successfully gets logged in and user session data stored in DB. But still req.isAuthenticated()
returning false.
I found the answer by invoking req.logIn
in my route after successful local login.
The problem seemed to be the passport.deserializeUser
was not being called.
I've referred to this problem Passport deserializeUser not being called
If you are using the authenticate callback when you authenticate with passport you need to log the user in manually. It will not be called for you.
This is what I've changed on my /authenticate
route.
router.post(
'/v1/authenticate',
validateBody(schemas.loginSchema),
(req, res, next) => {
passport.authenticate('local-login', (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
return res
.status(401)
.send(makeErrorJson({ type: INCORRECT_CREDENTIALS, status_code: 401, message: info.error }));
} else {
req.logIn(user, function (err) { // I added this <-- Log user in
if (err) {
return next(err);
}
console.log('LOGIN SUCCESS, IS AUTH: ', req.isAuthenticated())
const userData = sessionizeUser(user);
return res.status(200).send(userData);
});
}
})(req, res, next);
});