yhnavein/express-starter

View on GitHub
config/passport.js

Summary

Maintainability
F
4 days
Test Coverage
'use strict';

var passport = require('passport');
var Promise = require('bluebird');
var LocalStrategy = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;
var GitHubStrategy = require('passport-github').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var LinkedInStrategy = require('passport-linkedin-oauth2').Strategy;

var secrets = require('./secrets');
var db = require('../models/sequelize');
var UserRepo = require('../repositories/UserRepository');

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  db.User.findById(id).then(function(user) {
    done(null, user);
  }).catch(function(error) {
    done(error);
  });
});

/**
 * Sign in using Email and Password.
 */
passport.use(new LocalStrategy({ usernameField: 'email' }, function(email, password, done) {
  email = email.toLowerCase();
  db.User.findUser(email, password, function(err, user) {
    if(err)
      return done(err, null);
    return done(null, user);
  });
}));

/**
 * OAuth Strategy Overview
 *
 * - User is already logged in.
 *   - Check if there is an existing account with a provider id.
 *     - If there is, return an error message. (Account merging not supported)
 *     - Else link new OAuth account with currently logged-in user.
 * - User is not logged in.
 *   - Check if it's a returning user.
 *     - If returning user, sign in and we are done.
 *     - Else check if there is an existing account with user's email.
 *       - If there is, return an error message.
 *       - Else create a new account.
 */

/**
 * Sign in with Facebook.
 */
passport.use(new FacebookStrategy(secrets.facebook, function(req, accessToken, refreshToken, profile, done) {
  if (req.user) {
    UserRepo.linkFacebookProfile(req.user.id, accessToken, refreshToken, profile)
      .then(function(user) {
        req.flash('info', { msg: 'Facebook account has been linked.' });
        done(null, user);
      })
      .catch(function(err) {
        req.flash('errors', { msg: err });
        done(null, false, { message: err });
      });
  } else {
    UserRepo.createAccFromFacebook(accessToken, refreshToken, profile)
      .then(function(user) { done(null, user); })
      .catch(function(error) { done(error); });
  }
}));

/**
 * Sign in with GitHub.
 */
passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refreshToken, profile, done) {
  if (req.user) {
    UserRepo.linkGithubProfile(req.user.id, accessToken, refreshToken, profile)
      .then(function(user) {
        req.flash('info', { msg: 'GitHub account has been linked.' });
        done(null, user);
      })
      .catch(function(err) {
        req.flash('errors', { msg: err });
        done(null, false, { message: err });
      });
  } else {
    UserRepo.createAccFromGithub(accessToken, refreshToken, profile)
      .then(function(user) { done(null, user); })
      .catch(function(error) { done(error); });
  }
}));

/**
 * Sign in with Twitter.
 */
passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tokenSecret, profile, done) {
  if (req.user) {
    UserRepo.linkTwitterProfile(req.user.id, accessToken, tokenSecret, profile)
      .then(function(user) {
        req.flash('info', { msg: 'Twitter account has been linked.' });
        done(null, user);
      })
      .catch(function(err) {
        req.flash('errors', { msg: err });
        done(null, false, { message: err });
      });
  } else {
    UserRepo.createAccFromTwitter(accessToken, tokenSecret, profile)
      .then(function(user) { done(null, user); })
      .catch(function(error) { done(error); });
  }
}));

/**
 * Sign in with Google.
 */
passport.use(new GoogleStrategy(secrets.google, function(req, accessToken, refreshToken, profile, done) {
  if (req.user) {
    UserRepo.linkGoogleProfile(req.user.id, accessToken, refreshToken, profile)
      .then(function(user) {
        req.flash('info', { msg: 'Google account has been linked.' });
        done(null, user);
      })
      .catch(function(err) {
        req.flash('errors', { msg: err });
        done(null, false, { message: err });
      });
  } else {
    UserRepo.createAccFromGoogle(accessToken, refreshToken, profile)
      .then(function(user) { done(null, user); })
      .catch(function(error) { done(error); });
  }
}));

/**
 * Sign in with LinkedIn.
 */
passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, refreshToken, profile, done) {
  if (req.user) {
    UserRepo.linkLinkedInProfile(req.user.id, accessToken, refreshToken, profile)
      .then(function(user) {
        req.flash('info', { msg: 'LinkedIn account has been linked.' });
        done(null, user);
      })
      .catch(function(err) {
        req.flash('errors', { msg: err });
        done(null, false, { message: err });
      });
  } else {
    UserRepo.createAccFromLinkedIn(accessToken, refreshToken, profile)
      .then(function(user) { done(null, user); })
      .catch(function(error) { done(error); });
  }
}));

/**
 * Login Required middleware.
 */
exports.isAuthenticated = function(req, res, next) {
  if (req.isAuthenticated()) return next();
  res.redirect('/login');
};

/**
 * Authorization Required middleware.
 */
exports.isAuthorized = function(req, res, next) {
  var provider = req.path.split('/').slice(-1)[0];

  if (req.user.tokens[provider]) {
    next();
  } else {
    res.redirect('/auth/' + provider);
  }
};