Reputation: 2242
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);
});
};
Upvotes: 14
Views: 3162
Reputation: 8670
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.
Upvotes: 3
Reputation: 3572
Have you tried maxAge
?
app.use(express.session({ store: sessionStore,
cookie: { maxAge : 3600000 } //1 Hour
}));
Upvotes: 1