I am trying to configure basic authentication for my first public node application. I have two passport strategies: 1) for Facebook and 2) for Twitter. I do not plan to turn on the email / password system until I understand the security implications. I was able to get them to work in a box and bind Mongoose to create new users.
Now I want to work on deduplicating users of a social account. Therefore, whenever a new user arrives via twitter auth, I want to redirect them to a page that collects email. I save the token and profile object returned as session variables and will reuse them on this page when I submit the form as hidden fields.
However, I cannot figure out how to implement this aspect with Passport. Here is the code that I still have with comments on what I'm trying to do with each part. Essentially, I check if the twitter user is an old user, if not I set session variables that I will reuse on the / addemail page by initializing the user object (so that the Serialize, Deserialize function can do something (not sure if I understand what serialization / deserialization really does.) Now, if the user is new, the NewTwitterUser session variable is true, and I check it in the auth / callback URL to redirect the user to the corresponding page. However, this does not work a.
//basic modules and setup var express = require('express') , passport = require('passport') , mongoose = require('mongoose') , http = require('http') , util = require('util') , TwitterStrategy = require('passport-twitter').Strategy , FacebookStrategy = require('passport-facebook').Strategy , path = require('path'); var app = express(); //Mongodb setup var Schema = mongoose.Schema; var ObjectId = Schema.ObjectId; var UserSchema = new Schema({ provider: String, uid: String, fb_uid: String, twitter_uid: String, name: String, first_name: String, gender: String, fb_username: String, twitter_username: String, profile_pic: String, email: String, location: String, birthday: String, created: {type: Date, default: Date.now} }); var User = mongoose.model('User', UserSchema); mongoose.connect('MongoHQ db connection here')' //User Authentication - Twitter passport.use(new TwitterStrategy({ consumerKey: 'KEY', consumerSecret : 'SECRET', callbackURL: "CALLBACKURL", passReqToCallback: true }, function(req, token, tokenSecret, profile, done){ User.findOne({twitter_uid: profile.id}, function(err, user){ if (err) { console.log('this is an error 1' + err); return done(err);} if(user){ console.log('this user' + user); done(null, user); } else { console.log('this is a new user'); req.session.token = token; req.session.tokenSecret = tokenSecret; req.session.profile = profile; req.session.newtwitteruser = true; var user = new User(); user.uid = profile.id; done(null, user); /* This part is commented and is the default code I had if I needed to simply create a Twitter User right here. var user = new User(); user.provider = profile.provider; user.uid = profile.id; user.twitter_uid = profile.id; user.name = profile.displayName; user.first_name = profile.displayName[0]; user.twitter_username = profile._json.screen_name; user.profile_pic = profile._json.profile_image_url; user.location = profile._json.location; user.save(function(err){ if(err) {throw err;} else {done(null, user);} });*/ } }); } )); //User Authentication - Facebook passport.use(new FacebookStrategy({ clientID: 'ID', clientSecret: 'SECRET', callbackURL: "URL" }, function(accessToken, refreshToken, profile, done){ User.findOne({fb_uid: profile.id}, function(err, user){ if (err) {return done(err);} if(user){ done(null, user); } else { var user = new User(); user.provider = profile.provider; user.uid = profile.id; user.fb_uid = profile.id; user.name = profile.displayName; user.first_name = profile._json.first_name; user.gender = profile._json.gender; user.fb_username = profile._json.username; user.profile_pic = 'https://graph.facebook.com/' + profile.id + '/picture'; user.email = profile._json.email; user.location = profile._json.location.name; user.birthday = profile._json.birthday; user.save(function(err){ if(err) {throw err;} else {done(null, user);} }); } }) } )); passport.serializeUser(function(user, done) { done(null, user.uid); }); passport.deserializeUser(function(uid, done) { User.findOne({uid: uid}, function (err, user) { done(err, user); }); }); //app configurations app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser("freecookie")); app.use(express.session({secret:"freecookie"})); app.use(express.static(path.join(__dirname, 'public'))); app.use(express.errorHandler()); app.use(passport.initialize()); app.use(passport.session()); app.use(app.router); }); //Basic Routing app.get('/', function(req, res){ res.render('home', {title: 'App Title', user: req.user}); }); app.get('/auth/twitter', passport.authenticate('twitter')); app.get('/auth/twitter/callback', passport.authenticate('twitter', {failureRedirect: '/login' }), function(req, res) { if (req.session.newtwitteruser){ res.redirect('/addemail');} else {res.redirect('/');} }); app.get('/addemail', function(req, res){ if (req.session.newtwitteruser){ res.render('email', {title: 'Add your Email'});} else {res.redirect('/');} }); app.get('/auth/facebook', passport.authenticate('facebook', {scope: ['email', 'user_location', 'user_birthday'] })); app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect: '/', failureRedirect: '/login' })); app.get('/logout', function(req, res){ req.logout(); res.redirect('/'); }); //create the server var server = http.createServer(app); server.listen(app.get('port')); //Checks if a request is authenticated function ensureAuthenticated(req, res, next) { if (req.isAuthenticated()) { return next(); } res.redirect('/login') }