1. install packages
npm i bcrypt connect-mongo express-session passport passport-local
2. Add passport config
configs/passport.config.js
const User = require('../models/user.model');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
passport.serializeUser((user, next) => {
next(null, user.id);
});
passport.deserializeUser((id, next) => {
User.findById(id)
.then(user => next(null, user))
.catch(next)
});
passport.use('auth-local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
}, (email, password, next) => {
User.findOne({ email: email })
.then(user => {
if (!user) {
next(null, false, 'Invalid email or password')
} else {
return user.checkPassword(password)
.then(match => {
if (!match) {
next(null, false, 'Invalid email or password')
} else {
next(null, user)
}
})
}
})
.catch(error => next(error))
}));
3. Add session config
configs/session.config.js
const session = require('express-session');
const MongoStore = require("connect-mongo")(session);
const mongoose = require('mongoose');
module.exports = session({
secret: process.env.SESSION_SECRET || 'SuperSecret - (Change it)',
resave: false,
saveUninitialized: true,
cookie: {
secure: false,
httpOnly: true,
maxAge: 60 * 60 * 24 * 1000
},
store: new MongoStore({
mongooseConnection: mongoose.connection,
ttl: 24 * 60 * 60
})
});
4. Add User model
models/user.model.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const SALT_WORK_FACTOR = 10
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
minlength: 8
}
}, {
timestamps: true,
toJSON: {
virtuals: true,
transform: (doc, ret) => {
ret.id = doc._id;
delete ret._id;
delete ret.__v;
delete ret.password;
return ret;
}
}
})
userSchema.pre('save', function (next) {
const user = this;
if (!user.isModified('password')) {
next();
} else {
bcrypt.genSalt(SALT_WORK_FACTOR)
.then(salt => {
return bcrypt.hash(user.password, salt)
.then(hash => {
user.password = hash;
next();
})
})
.catch(error => next(error))
}
});
userSchema.methods.checkPassword = function (password) {
return bcrypt.compare(password, this.password);
}
const User = mongoose.model('User', userSchema);
module.exports = User;
5. Add auth routes
routes/auth.routes.js
const express = require('express');
const router = express.Router();
const secure = require('../middlewares/secure.mid');
const authController = require('../controllers/auth.controller');
router.post('/register', authController.register);
router.post('/authenticate', authController.authenticate);
router.post('/logout', secure.isAuthenticated, authController.logout);
module.exports = router;
6. Add auth controller
controllers/auth.controller.js
const User = require('../models/user.model');
const createError = require('http-errors');
const passport = require('passport');
module.exports.register = (req, res, next) => {
const { email } = req.body;
User.findOne({ email: email })
.then(user => {
if (user) {
throw createError(409, 'Email already registered')
} else {
return new User(req.body).save();
}
})
.then(user => res.status(201).json(user))
.catch(next)
}
module.exports.authenticate = (req, res, next) => {
passport.authenticate('auth-local', (error, user, message) => {
if (error) {
next(error);
} else if (!user) {
next(createError(401, message));
} else {
req.login(user, (error) => {
if (error) {
next(error)
} else {
res.status(201).json(user);
}
})
}
})(req, res, next);
}
module.exports.logout = (req, res, next) => {
req.logout();
res.status(204).json();
}
7. Add secure middleware
middlewares/secure.mid.js
const createError = require('http-errors');
module.exports.isAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
next(createError(401));
}
}
8. Add middleware to protected routes
routes/whatever.route.js
// ...
const secure = require('../middlewares/secure.mid');
router.get('/', secure.isAuthenticated, controller.list);
// ...
9. setup app.js
app.js
const passport = require('passport');
// ...
require('./configs/passport.config');
const session = require('./configs/session.config');
// ...
const authRouter = require('./routes/auth.routes');
// ...
app.use(session)
app.use(passport.initialize());
app.use(passport.session());
//...
app.use('/', authRouter);