Using Passport, Bcrypt, Express, & Handlebars in a Nodejs Full-Stack App for User Authentication

Roberto Baldizon
Jun 19, 2018 · 8 min read
require("dotenv").config();var express = require("express");
var bodyParser = require("body-parser");
var exphbs = require("express-handlebars");
var passport = require('passport');
var flash = require('connect-flash');
var cookieParser = require('cookie-parser');
var session = require('express-session');

var app = express();
var PORT = process.env.PORT || 8080;

var db = require("./models");

require('./config/passport')(passport);

app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());


app.engine("handlebars", exphbs({defaultLayout: "main"}));
app.set("view engine","handlebars");

app.use(express.static("public"));

app.use(session({
key: 'user_sid',
secret: 'goN6DJJC6E287cC77kkdYuNuAyWnz7Q3iZj8',
resave: false,
saveUninitialized: false,
cookie: {
expires: 600000
}
}));

app.use(passport.initialize());
app.use(passport.session());
app.use(flash());

require("./controllers/html-routes")(app, passport);
require("./controllers/account-controller")(app, passport);
require("./controllers/item-controller")(app, passport);
require("./controllers/search-controller")(app, passport);
require("./controllers/transactions-controller")(app, passport);


db.sequelize.sync().then(function(){
app.listen(PORT, function(){
console.log("Listening on localhost:" + PORT);
})
})

var LocalStrategy = require('passport-local').Strategy;

var db = require('../models');

module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.uuid);
});

passport.deserializeUser(function(uuid, done) {
db.Accounts.findById(uuid).then(function(user) {
if (user) {
done(null, user.get());
} else {
done(user.errors, null);
}
});
});

passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField : 'account_key',
passReqToCallback : true
},

function(req, email, account_key, done) {
process.nextTick(function() {
db.Accounts.findOne({
where: {
email: email
}
}).then(function(user, err){
if(err) {
console.log("err",err)
return done(err);
}
if (user) {
console.log('signupMessage', 'That email is already taken.');
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
db.Accounts.create({
first_name:req.body.first_name,
last_name:req.body.last_name,
street: req.body.street,
city: req.body.city,
state: req.body.state,
zip: req.body.zip,
balance: req.body.balance,
email: req.body.email,
phone: req.body.phone,
account_key: db.Accounts.generateHash(account_key)

}).then(function(dbUser) {


return done(null, dbUser);

}).catch(function (err) { console.log(err);});
}
});
});
}));

passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField : 'account_key',
passReqToCallback : true
},

function(req, email, account_key, done) { 
db.Accounts.findOne({
where: {
email: req.body.email
}
}).then(function(user, err) {
(!user.validPassword(req.body.account_key)));
if (!user){
console.log("no user found");
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (user && !user.validPassword(req.body.account_key)){
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
}
return done(null, user);
});
}));

};

module.exports = function(app){
app.get("/", function(req,res){
if(req.isAuthenticated()){
var user = {
id: req.session.passport.user,
isloggedin: req.isAuthenticated()
}
res.render("home", user);
}
else{
res.render("home");
}
})

app.get("/list-items", function(req,res){
res.render("search");
});

app.get("/signup", function(req,res){
if(req.isAuthenticated()){
res.redirect("/acounts/view");
}else{
res.render("accounts");
}
});

app.get("/add-items", function(req, res){
if(req.isAuthenticated()){
res.render("add-items");
}else {
res.redirect()
}
})
};

var uuidv1  = require('uuid/v1');
var bcrypt = require('bcrypt');

module.exports = function(sequelize, DataTypes) {
var Accounts = sequelize.define("Accounts", {
uuid: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV1,
isUnique :true
},
first_name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [1, 30]
}
},
last_name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [1, 30]
}
},
street: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [1, 30]
}
},
city: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [1, 30]
}
},
state: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [1, 2]
}
},
zip: {
type: DataTypes.INTEGER,
allowNull: false,
validate: {
len: [5]
}
},
balance: {
type: DataTypes.DECIMAL(12, 2),
defaultValue: 0
},
email: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [1, 100]
}
},
phone: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [10]
}
},
account_key: {
type: DataTypes.STRING,
required: true,
validate: {
len:[8]
}
}

});

// methods ======================
// generating a hash
Accounts.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};

// checking if password is valid
Accounts.prototype.validPassword = function(password) {
return bcrypt.compareSync(password, this.account_key);
};

Accounts.associate = function(models){
Accounts.hasMany(models.Items, {
foreignKey: "owner_id",
onDelete: "cascade"
});
};

Accounts.associate = function(models){
Accounts.hasMany(models.Transactions, {
foreignKey: "renter_id"
});
};

return Accounts;
}

var db = require("../models");

var passport = require('passport');

module.exports = function (app) {

app.get("/signup", function (req, res) {
res.render("accounts");
});

app.get("/accounts/view", function (req, res) {
console.log("%%%%%%%%% is logged in", req.isAuthenticated());

if(req.isAuthenticated()){

db.Accounts.findOne({
where:{
uuid: req.session.passport.user
}
}).then(function(dbUser){
var user = {
userInfo: dbUser.dataValues,
id: req.session.passport.user,
isloggedin: req.isAuthenticated()
}
res.render("view-account", user);
})
}
else {
var user = {
id: null,
isloggedin: req.isAuthenticated()
}
res.redirect("/");
}
});

    app.get('/logout', function(req, res) {
req.session.destroy(function(err){
req.logout();
res.clearCookie('user_sid');
res.clearCookie('first_name');
res.clearCookie('user_id');
res.redirect('/');
})
});
app.post('/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err, user, info) {
console.log("info", info);
if (err) {
console.log("passport err", err);
return next(err); // will generate a 500 error
}
if (! user) {
console.log("user error", user);
return res.send({ success : false, message : 'authentication failed' });
}
req.login(user, loginErr => {
if (loginErr) {
console.log("loginerr", loginerr)
return next(loginErr);
}
console.log('redirecting....');
res.cookie('first_name', user.first_name);
res.cookie('user_id', user.uuid );
return res.redirect("/accounts/view");
});
})(req, res, next);
});

app.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
console.log("\n\n\n########userrrr", user)
if (err) {
console.log("passport err", err);
return next(err); // will generate a 500 error
}
if (!user) {

return res.send({ success : false, message : 'authentication failed'});
}
req.login(user, loginErr => {
if (loginErr) {
console.log("loginerr", loginErr)
return next(loginErr);
}

console.log('redirecting....')
res.cookie('first_name', user.first_name);
res.cookie('user_id', user.uuid );

return res.json(true);

});
})(req, res, next);
});
}



Silibrain

Shared thoughts, ideas, opinions, research, tips, and more from innovative & passionate people trying to fix the world's problems through the use of technology!

Roberto Baldizon

Written by

Engineer experienced in web-apps, software, and energy systems design. Used to getting my hands dirty to find tailored technology solutions with real value.

Silibrain

Silibrain

Shared thoughts, ideas, opinions, research, tips, and more from innovative & passionate people trying to fix the world's problems through the use of technology!