PassportJS Authentication in Node.JS in 48 Small Steps
- Install Node.JS
- Create an account with MongoDB Atlas
- Create Node.JS project
- npm init
- Install dependencies
- npm install --save express bcryptjs passport ejs express-ejs-layout mongoose connect-flash express-session
- Install nodemon to restart server on every save
- npm install -D nodemon
- Add to scripts in package.json the following
- "scripts":{"start":"node app.js", "dev":"nodemon app.js"}
- Create app.js file
- Add boiler plate express
- const express = require("express");
- const app = express();
- const PORT = process.env.PORT || 5000;
- app.listen(PORT, console.log(`Server started on PORT ${PORT}`));
- Run the following in terminal
- npm run dev
- Create folder routes
- Create two files inside routes
- index.js
- users.js
- Inside routes/index.js add the following
- const express = require("express");
- const router = express.Router();
- router.get('/', (req, res) => res.send("Welcome"));
- module.exports = router;
- Inside app.js add the following under const app = express();
- app.use('/', require('./routes/index'));
- Open localhost:5000 in browser
- Inside routes/users.js add the following
- const express = require("express");
- const router = express.Router();
- router.get('/login', (req, res) => res.send("Login"));
- router.get('/register', (req, res) => res.send("Register"));
- module.exports = router;
- Inside app.js add the following under const app = express();
- app.use('/users', require('./routes/users'));
- Open localhost:5000/users/login in browser
- Open localhost:5000/users/register in browser
- Add express in app.js
- const expressLayouts = require('express-ejs-layouts');
- const app = express();
- app.use(expressLayouts);
- app.set('view engine', 'ejs');
- Create folder named views
- Add the following files in Views folder
- layout.ejs
- welcome.ejs
- login.ejs
- register.ejs
- dashboard.ejs
- Include boilerplate html in all the ejs files
- Import bootstrap css and javascript files in all ejs or create a common head and put it there and include the head in all ejs files.
- Change routes/index.js file
- Instead of res.send('Welcome'); use res.render('welcome');
- Change routes/users.js file
- Instead of res.send('Login'); use res.render('login');
- Instead of res.send('Register'); use res.render('register');
- To connect to mongoDB database using Mongoose add the following to app.js
- const mongoose = require("mongoose");
- const db = process.env.MONGOURI;
- mongoose.connect(db, { newUrlParser: true }).then(() => console.log("MongoDB Connected").catch(err => console.error(err)));
- Create folder called Model
- Create a file in Model folder and name it User.js
- Inside User.js add the following:
- const mongoose = require('mongoose');
- const UserSchema = new mongoose.Schema({name: {type: String, required: true}, email: {type: String, required: true}, password: {type: String, required: true}, date: {type: Date, default: Date.now},});
- const User = mongoose.model('User', UserSchema);
- module.exports = User;
- Add bodyparser below declaring ejs as view engine
- app.use(express.urlencoded({ extended: false }));
- In router/register import bcrypjs
- const bcrypt = require('bcryptjs');
- Add a post router in register
- router.post('/register', (req, res) => {
- const { name, email, password, password2 } = req.body;
- let errors = [];
- if(!name || !email || !password || !password2) {
- errors.push({ msg: "Please fill in all fields" })
- }
- if(password !== password2) {
- errors.push({ msg: "Passwords do not match" })
- }
- if(password.length < 6) {
- errors.push({ msg: "Password should be at least 6 characters long" })
- }
- if(errors.length > 0) {
- res.render('register', { errors, name, email, password, password2 });
- } else {
- User.findOne({email: email}).then(user => {
- if(user) {
- errors.push({msg: 'Email si already registered.'});
- res.render('register', { errors, name, email, password, password2 });
- } else {
- const newUser = new User({ name, email, password });
- bcrypt.genSalt(10, (err, salt) => bcrypt.hash(newUser.password, salt, (err, hash) => {
- if(err) throw err;
- newUser.password = hash;
- newUser.save().then(user => {
- req.flash('success_msg', 'You are now registered and can log in!');
- res.redirect('/users/login');
- ).catch(err => console.error(err));
- }));
- newUser.save();
- res.send(newUser);
- }
- })
- }
- });
- Display error in frontend to display if any of the defined error occurs
- Include flash and session in app.js
- const flash = require('connect-flash');
- const session = require('express-session');
- Below defining body parser define Express Session
- app.user(session({
- secret: 'MYsecret',
- resave: true,
- saveUninitialized: true
- }));
- Below defining Express Session, define Connect Flash
- app.use(flash());
- Below defining flash, define global variables
- app.use((req, res, next) => {
- res.locals.success_msg = req.flash('success_msg');
- res.locals.error_msg = req.flash('error_msg');
- next();
- });
- Display the success message in frontend using if (success_msg != '') {}
- Display the error message in frontend using if (error_msg != '') {}
- Create a file named passport.js
- const LocalStrategy = require('passport-local').Strategy;
- const mongoose = require('mongoose');
- const bcrypt = require('bcryptjs'); // Load User model
- const User = require('../models/User');
- module.exports = function(passport) {
- passport.use( new LocalStrategy({ usernameField: 'email' }, (email, password, done) => { // Match user
- User.findOne({ email: email })
- .then(user => {
- if (!user) {
- return done(null, false, { message: 'That email is not registered' });
- } // Match password
- bcrypt.compare(password, user.password, (err, isMatch) => {
- if (err) throw err;
- if (isMatch) {
- return done(null, user);
- } else {
- return done(null, false, { message: 'Password incorrect'
- });
- }
- });
- });
- })
- );
- passport.serializeUser(function(user, done) {
- done(null, user.id);
- });
- passport.deserializeUser(function(id, done) {
- User.findById(id, function(err, user) {
- done(err, user);
- });
- });
- };
- Import passport in app.js
- const passport = require('passport');
- require('./passport').(passport);
- Inside app.js after Express Session middleware add the following middleware:
- app.use(passport.initialize());
- app.use(passport.session());
- Import password in routes/users.js
- const passport = require('passport');
- Add the following POST function to routes/users.js
router.post('/login', (req, res, next) => { // Login passport.authenticate('local', { successRedirect: '/dashboard', failureRedirect: '/users/login', failureFlash: true })(req, res, next); }); router.get('/logout', (req, res) => { // Logout req.logout(); req.flash('success_msg', 'You are logged out'); res.redirect('/users/login'); }); - Inside routes/index.js add the following
- const express = require('express');
- const router = express.Router();
- const { ensureAuthenticated, forwardAuthenticated } = require('./auth');
- // Welcome Page
- router.get('/', forwardAuthenticated, (req, res) => res.render('welcome'));
- // Dashboard
- router.get('/dashboard', ensureAuthenticated, (req, res) =>
- res.render('dashboard', {
- user: req.user
- })
- );
- module.exports = router;
- Create a file named auth.js
- module.exports = {
- ensureAuthenticated: function(req, res, next) {
- if (req.isAuthenticated()) {
- return next();
- }
- req.flash('error_msg', 'Please log in to view that resource');
- res.redirect('/users/login');
- },
- forwardAuthenticated: function(req, res, next) {
- if (!req.isAuthenticated()) {
- return next();
- }
- res.redirect('/dashboard');
- }
- };
Watch video tutorial here: https://www.youtube.com/watch?v=6FOq4cUdH8k&t
Comments
Post a Comment