I have an app using passport.js to log in users through facebook, and am attempting to use express-mysql-session to persist their login states. If I don't include the express-mysql-session code, the passport serializeUser and deserializeUser functions hit fine...however when I un-comment the code that attempts to store their session with express-mysql-session, the deserializeUser function doesn't get hit, and the user never gets properly logged in.
server.js file
var express = require('express'); var mysql = require('mysql'); var passport = require('passport'); var session = require('express-session'); var MySQLStore = require('express-mysql-session')(session); if (typeof process.env.OPENSHIFT_MYSQL_DB_HOST === "undefined"){ var options = { host : 'localhost', port : '3307', user : 'user', password : 'password', database : 'database', socketpath: '/var/run/mysqld/mysqld.sock' } } else { var options = { host : process.env.OPENSHIFT_MYSQL_DB_HOST, port : process.env.OPENSHIFT_MYSQL_DB_PORT, user : process.env.OPENSHIFT_MYSQL_DB_USERNAME, password : process.env.OPENSHIFT_MYSQL_DB_PASSWORD, database : process.env.OPENSHIFT_APP_NAME, socket : process.env.OPENSHIFT_MYSQL_DB_SOCKET } }; var connection = mysql.createConnection(options); var sessionStore = new MySQLStore({ checkExpirationInterval: 900000,// How frequently expired sessions will be cleared; milliseconds. expiration: 86400000,// The maximum age of a valid session; milliseconds. createDatabaseTable: false,// Whether or not to create the sessions database table, if one does not already exist. connectionLimit: 1, schema: { tableName: 'LoginRequests', columnNames: { session_id: 'loginID', expires: 'expires', data:'data' } } }, connection); self.initializeServer = function() { self.app = module.exports = express(); self.app.configure(function() { self.app.set('views', __dirname + '/public'); self.app.set('view engine', 'html'); self.app.engine('html', require('hogan-express')); self.app.enable('view cache'); self.app.use(express.favicon()); self.app.use(express.logger('dev')); self.app.use(express.bodyParser()); self.app.use(express.methodOverride()); self.app.use(express.cookieParser('secret')); self.app.use(session({ key: 'session_cookie_name', secret: 'secret', cookie: {maxAge: 3600000, secure:false}, store: sessionStore, resave: false, saveUninitialized: false })); // required for passport self.app.use(passport.initialize()); self.app.use(passport.session()); // persistent login sessions self.app.use(express.static(path.join(__dirname, 'public'))); self.app.use('/public',express.static(__dirname, '/public')); self.app.use(self.app.router); //self.app.use(require('stylus').middleware(__dirname + '/public')); }); require('./routes/site.js'); require('./config/passport.js')(passport); // pass passport for configuration }
So, if I comment out the "store" option in the session object above, the passport functions get hit. If I leave this line un-commented, the deserializeUser function does not get hit.
Passport functions
passport.serializeUser(function(user, done) { console.log('you have been serialized!'); done(null, user.id); }); // used to deserialize the user passport.deserializeUser(function(id, done) { console.log('you have been deserialized!'); connection.query("SELECT * FROM Users WHERE id = "+id,function(err,rows){ done(err, rows[0]); }); });
EDIT
Mor Paz suggested that I include some of the logs from when I run my server with the debug module. Below are the logs right before, and immediately after the user is serialized. The user should be deserialized at some point near this, but never is.
GET /auth/facebook 302 81ms - 412b express-mysql-session:log Getting session: oNcJ4UapxCY_zKOyfSBTUWaVhaNZuFRq +356ms you are a user! you have been serialized! express-mysql-session:log Setting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +798ms express-mysql-session:log Getting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +6ms GET /auth/facebook/callback? code=AQCWPvA5ZRMYoTueW6_wWU49Up5ggjW68ufOtiYkU5IzhRjSNyyWnzlQVprgQo_uubQkEVvNI0yo53ET3cWBnDAHUGmAXPBy_ITEmC-biE2KEGEr0iCm_cqjuG90nnePY-k9U2oFUbX2kvLgMeM0kZ-094EHiU_NJjmAJNj6mzTkSE47935RhJy0Tba_sYS88_C0N3kn5f5kcoTC4KsgW1gBHWWJAwZ68Lj94ffVe2hN97580CtzEpJa0wwQHwTBYfmjQ0NfUdx07m4rXW9R7PR06aHDcUDrYqR9Kb0LWq4sZLbQjV5rI7gzkWG-huhq7IY 302 825ms - 72b express-mysql-session:log Setting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +56ms express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +23ms express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +2ms GET /profile 200 84ms - 4.22kb
It was impossible to replicate the problem, so I prepared a working example. [Github repo.]
Its crafted for Openshift, since I saw the usage of its environment variables (it can be adapted with ease for other use cases).
I did some modifications to the original concept :
self = this
conceptI hope it can be useful as a starting point.
// .: DB Configuration :. const mysql = require('mysql'); var dbconf = {host:process.env.OPENSHIFT_MYSQL_DB_HOST,port:process.env.OPENSHIFT_MYSQL_DB_PORT,user:process.env.OPENSHIFT_MYSQL_DB_USERNAME,password:process.env.OPENSHIFT_MYSQL_DB_PASSWORD,database:process.env.OPENSHIFT_APP_NAME,socket:process.env.OPENSHIFT_MYSQL_DB_SOCKET}} const dbconn = mysql.createConnection(dbconf); /*or create a pool*/ dbconn.connect(); // .: Express & Other Middleware Modules :. var express = require('express'); var path = require('path'); var bodyParser = require('body-parser'); var methodOverride = require('method-override'); var cookieParser = require('cookie-parser'); var serveStatic = require('serve-static'); // .: Sessions :. var passport = require('passport'); var GitHubStrategy = require('passport-github2'); var session = require('express-session'); var MySQLStore = require('express-mysql-session')(session); var sessionStoreConf = { connectionLimit:1,checkExpirationInterval:900000,expiration:86400000, createDatabaseTable:true,schema:{tableName:'LoginRequests',columnNames:{session_id:'loginID',expires:'expires',data:'data'}} }; var sessionStore = new MySQLStore(sessionStoreConf,dbconn); // .: Server (class) :. class Server { constructor(port, ip){ this.app = express(); this.app.use(cookieParser('secret')); this.app.use(session({ key:'session_cookie_name', secret:'secret', cookie:{maxAge:3600000,secure:false}, store: sessionStore, resave:false, saveUninitialized:false })); this.app.use(passport.initialize()); this.app.use(passport.session()); this.app.use(serveStatic(path.join(__dirname,'public'))) this.app.listen(port,ip,function(){console.log('[i] Application worker started.');}); //require('./routes/site.js'); //~Example (routes/site.js) : this.app.get("/",function(req,res){res.send("<a href='./auth/github'>Click here to login (GitHub)</a>");}) this.app.get('/auth/github',passport.authenticate('github',{scope:['user:email']})); this.app.get('/auth/github/callback',passport.authenticate('github',{failureRedirect:'/'}),function(req,res){res.redirect('/success');}); // route for valid logins this.app.get('/success', function(req, res){ if(req.user){ console.log(req.user); res.send(req.user); } else{ res.redirect('/login'); } }); // route to check the sessionStore table entries in the browser this.app.get('/sessions',function(req,res){ dbconn.query("SELECT * FROM LoginRequests",function(err,rows){ if(err){console.log(err);}else{ if(rows.length!=0){ res.send(JSON.stringify(rows)); console.log(rows); }else{res.send("No LoginRequests found");} } }); }); //require('./config/passport.js')(passport); //~Example (config/passport.js) : passport.use(new GitHubStrategy( {clientID:"clientID",clientSecret:"clientSecret",callbackURL:"callbackURL"}, function(token, tokenSecret, user, cb){CheckUser('github',user,cb);} )); } } const server = new Server(process.env.OPENSHIFT_NODEJS_PORT,process.env.OPENSHIFT_NODEJS_IP); // .: Passport : Serialize & Deserialize User :. passport.serializeUser(function(user, done){ console.log('[passport] serializeUser'); done(null,user.id); }); passport.deserializeUser(function(id, done) { console.log('[passport] deserializeUser'); dbconn.query("SELECT * FROM Users WHERE id=?",[id],function(err,rows){ if(err){console.log(err);}else{ if(rows.length!=0){ done(err,rows[0]); } else{ done(err,null); } } }); }); //:Check if user exists: function CheckUser(platform,user,cb){ dbconn.query("SELECT * FROM Users WHERE id=?",[user.id],function(err,rows){ if(err){console.log(err); cb(err,null);}else{ if(rows.length!=0){cb(null,user);} else{CreateUser(platform,user,cb);} } }); } //:Create new user: function CreateUser(platform,user,cb){ switch(platform){ case "github": var newUserObj = {id:user.id,platform:platform,email:user.emails[0].value}; dbconn.query("INSERT INTO Users SET ?",newUserObj,function(err){ if(err){console.log(err); cb(err,null);}else{cb(null,user);} }); break; default: console.log("[error] (createUser) : platform not implemented :",platform); cb(err,null); break; } }
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