I have got 200 response for login request, but 401 for any futher auth check requests, because deserializeUser never called. I dived into passport source and noticed that passport checks whether req._passport.session.user exists, and if no it doesn't call deserializeUser.
I have searched through other questions on stackoverflow, it seems i have specific case.
There is single local strategy auth type, i use Ajax request to make login requests, CORS settings configured, http://localhost:8080 - frontend, http://localhost:3000 backend)
I use bodyParse, cookieParser, express session, passport initialize and passport sessions. Express session secure:false configured as i run auth requests through http.
You can find my project here (backend package.json is good to go, so you can use it, it has no missing dependencies, as for frontend not sure), at least you can check the code there.
Backend https://github.com/rantiev/template-api Frontend https://github.com/rantiev/template-angular
Express session configuration and CORS is here https://github.com/rantiev/template-api/blob/master/modules/appConfigure.js
var path = require('path');
var bodyParser = require('body-parser');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var MongoStore = require('connect-mongo')(session);
module.exports = function (app, express, config, mongoose) {
app.use(cookieParser());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, X-AUTHENTICATION, X-IP, Content-Type, Origin, Accept, Cookie');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
/*app.use(function (req, res, next) {
console.log('coockie is:', req.cookies);
});*/
app.use(session({
saveUninitialized: false,
resave: false,
secret: config.sessionsSecretToken,
cookie: {
secure: false
},
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(express.static(path.join(__dirname, '..' , 'public')));
};
Passport configuration is here https://github.com/rantiev/template-api/blob/master/api/authentication/authenticationR.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var rememberMe = require('../../modules/rememberMe');
var createAccessToken = require('../../modules/createAccessToken');
var bcrypt = require('bcrypt-nodejs');
var UserM = require('../users/userM');
module.exports = function (app, mainRouter, role) {
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
}, function (username, password, done) {
UserM.findOneQ({email: username})
.then(function(user){
if (user && bcrypt.compareSync(password, user.password)) {
done(null, user);
} else {
done(null, false);
}
})
.catch(function(err){
done(err);
});
}));
passport.serializeUser(function (user, done) {
console.log('serialize');
if (user) {
createAccessToken(user, done);
} else {
done(null, false);
}
});
passport.deserializeUser(function (token, done) {
console.log('deserialize');
UserM.findOneQ({accessToken: token})
.then(function(user){
if (user) {
done(null, user);
} else {
done(null, false);
}
})
.catch(function(err){
done(err);
});
});
app.use(passport.initialize());
app.use(passport.session());
mainRouter.post('/me', passport.authenticate('local'), function (req, res) {
res.status(200).send();
});
mainRouter.get('/logout', function (req, res) {
req.logout();
res.redirect('/');
});
mainRouter.get('/me', function (req, res) {
if (!req.user) {
res.status(401).send('Please Login!');
return;
}
var currentUser = {
id: req.user._id,
role: req.user.role
};
res.status(200).json(currentUser);
});
};
Passport is a popular, modular authentication middleware for Node. js applications. With it, authentication can be easily integrated into any Node- and Express-based app. The Passport library provides more than 500 authentication mechanisms, including OAuth, JWT, and simple username and password based authentication.
Passport's local strategy is a Node. js module that allows you to implement a username/password authentication mechanism. You'll need to install it like any other module and configure it to use your User Mongoose model.
The “Passport JS” library connects with the “expression-session” library, and forms the basic scaffolding to attach the (authenticated) user information to the req. session object. The main Passport JS library deals with already authenticated users, and does not play any part in actually authenticating the users.
If you look in your call stack and find that deserializeUser
is not being called because req._passport.session.user
is not set, then your problem is as follows. The offending lines are in the express-session
module:
if (!req.sessionID) {
debug('no SID sent, generating session');
generate();
next();
return;
}
If sessionID is set, generate
is never called:
store.generate = function(req){
req.sessionID = generateId(req);
req.session = new Session(req); // THIS
req.session.cookie = new Cookie(cookieOptions);
if (cookieOptions.secure === 'auto') {
req.session.cookie.secure = issecure(req, trustProxy);
}
};
But it is possible to have req.sessionID
set, while req.session
is null, which explains req._passport.session.user
being null—req.session
is never set.
I continued to trace back even further to when req.sessionID
is set, which, with new cookies, was sometimes being set and sometimes not.
Why? I don't know, and would love for someone to investigate further, but, basically, the lesson is try using the cookie-session
module instead.
Have you tried maxAge
?
app.use(express.session({ store: sessionStore,
cookie: { maxAge : 3600000 } //1 Hour
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With