BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

MEAN Stack : Authentication with Passport 2

MEAN-Icon.png




Bookmark and Share





bogotobogo.com site search:








Note

This tutorial is not much different from the previous one: Authentication with Passport.

In this tutorial, we will use the Local Authentication Strategy of Passport and authenticate the users against a locally configured Mongo DB instance.





passport-local2

Let's generate a boilerplate application by simply executing:

$ express passport-local2

passport-local2-tree1.png



package.json - dependencies

Let's install dependencies:

{
  "name": "passport-local2",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "repository": {
    "type": "git",
    "url": "git@github.com:epic-math/NodeJS-MEAN.git"
  },
  "author": "K Hong <k@epicmath.com>",
  "license": "MIT",
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "express": "~4.2.0",
    "jade": "~1.11.0",
    "morgan": "~1.6.1",
    "serve-favicon": "~2.3.0",
    "passport": "^0.2.0",
    "passport-local": "^1.0.0",
    "passport-local-mongoose": "^1.0.0",
    "mongoose": "~3.8.12",
    "express-session": "~1.11.3",
    "bcrypt-nodejs" : "*",
    "connect-flash" : "*"
  }
}

With the package.json, let's install dependencies:

$ pwd
/home/ubuntu/passport-local2

$ sudo npm install

Note that we added the dependencies for passport and passport-local module.


passport-tree2.png

WelcomeToExpress.png




Mongoose Model

Let's create a User Model in Mongoose which we can perform CRUD operations on the underlying database. The user model will be saved in models/user.js:

Let's install MongoDB:

var mongoose = require('mongoose');
 
module.exports = mongoose.model('User',{
    username: String,
    password: String,
    email: String,
    gender: String,
    address: String
});




Mongo configuration

Here is the updated app.js:

var mongoose = require('mongoose');
...
// mongoose
mongoose.connect('mongodb://localhost/passport_local_mongoose_express4');




Passport configuring

Passport provides the mechanism to handle authentication leaving the onus of implementing session-handling ourselves and for that we will be using express-session. Let's modify app.js:

// Configuring Passport
var passport = require('passport');
var expressSession = require('express-session');
app.use(expressSession({secret: 'mySecret'}));
app.use(passport.initialize());
app.use(passport.session());

This is needed as we want our user sessions to be persistent in nature. Before running the app, we need to install express-session and add it to our dependency list in package.json:

$ npm install --save express-session

passport-tree4.png



Serializing and deserializing user instances

Passport also needs to serialize and deserialize user instance from a session store in order to support login sessions, so that every subsequent request will not contain the user credentials. It provides two methods serializeUser and deserializeUser for this purpose:

passport.serializeUser(function(user, done) {
  done(null, user._id);
});
 
passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});




passport/login.js

We will now define Passport's strategies for handling login. It would be an instance of the Local Authentication Strategy of Passport and would be created using the passport.use() function. We use connect-flash to help us with error handling by providing flash messages which can be displayed to user on error.

var LocalStrategy   = require('passport-local').Strategy;
var User = require('../models/user');
var bCrypt = require('bcrypt-nodejs');

module.exports = function(passport){

	passport.use('login', new LocalStrategy({
            passReqToCallback : true
        },
        function(req, username, password, done) { 
            // check in mongo if a user with username exists or not
            User.findOne({ 'username' :  username }, 
                function(err, user) {
                    // In case of any error, return using the done method
                    if (err)
                        return done(err);
                    // Username does not exist, log the error and redirect back
                    if (!user){
                        console.log('User Not Found with username '+username);
                        return done(null, false, req.flash('message', 'User Not found.'));                 
                    }
                    // User exists but wrong password, log the error 
                    if (!isValidPassword(user, password)){
                        console.log('Invalid Password');
                        return done(null, false, req.flash('message', 'Invalid Password')); // redirect back to login page
                    }
                    // User and password both match, return user from done method
                    // which will be treated like success
                    return done(null, user);
                }
            );

        })
    );


    var isValidPassword = function(user, password){
        return bCrypt.compareSync(password, user.password);
    }
    
}

The first parameter to passport.use() is the name of the strategy which will be used to identify this strategy when applied later. The second parameter is the type of strategy that you want to create, here we use the username-password or the LocalStrategy.

passport.use('login', new LocalStrategy({
    passReqToCallback : true
  },

It is to be noted that by default the LocalStrategy expects to find the user credentials in username & password parameters, but it allows us to use any other named parameters as well. The passReqToCallback config variable allows us to access the request object in the callback, thereby enabling us to use any parameter associated with the request.

Next, we use the Mongoose API to find the User in our underlying collection of Users to check if the user is a valid user or not. The last parameter in our callback : done denotes a useful method using which we could signal success or failure to Passport module.

function(req, username, password, done) { 
   ...
    );

To specify failure either the first parameter should contain the error, or the second parameter should evaluate to false. To signify success the first parameter should be null and the second parameter should evaluate to a true value, in which case it will be made available on the request object.

Since passwords are inherently weak in nature, we should always encrypt them before saving them to the database. For this, we use bCrypt to help us out with encryption and decryption of passwords.

var isValidPassword = function(user, password){
  return bCrypt.compareSync(password, user.password);
}




passport/register.js

Now we want to define the next strategy which will handle registration of a new user entry in our underlying Mongo DB:

passport.use('signup', new LocalStrategy({
    passReqToCallback : true
  },
  function(req, username, password, done) {
    findOrCreateUser = function(){
      // find a user in Mongo with provided username
      User.findOne({'username':username},function(err, user) {
        // In case of any error return
        if (err){
          console.log('Error in SignUp: '+err);
          return done(err);
        }
        // already exists
        if (user) {
          console.log('User already exists');
          return done(null, false, 
             req.flash('message','User Already Exists'));
        } else {
          // if there is no user with that email
          // create the user
          var newUser = new User();
          // set the user's local credentials
          newUser.username = username;
          newUser.password = createHash(password);
          newUser.email = req.param('email');
          newUser.firstName = req.param('firstName');
          newUser.lastName = req.param('lastName');
 
          // save the user
          newUser.save(function(err) {
            if (err){
              console.log('Error in Saving user: '+err);  
              throw err;  
            }
            console.log('User Registration succesful');    
            return done(null, newUser);
          });
        }
      });
    };
     
    // Delay the execution of findOrCreateUser and execute 
    // the method in the next tick of the event loop
    process.nextTick(findOrCreateUser);
  });
);




routes/index.js

We now define our routes for the application in routes/index.js module which takes the instance of Passport created in app.js:

var express = require('express');
var router = express.Router();

var isAuthenticated = function (req, res, next) {
	// if user is authenticated in the session, call the next() to call the next request handler 
	// Passport adds this method to request object. A middleware is allowed to add properties to
	// request and response objects
	if (req.isAuthenticated())
		return next();
	// if the user is not authenticated then redirect him to the login page
	res.redirect('/');
}

module.exports = function(passport){

	/* GET login page. */
	router.get('/', function(req, res) {
    	// Display the Login page with any flash message, if any
		res.render('index', { message: req.flash('message') });
	});

	/* Handle Login POST */
	router.post('/login', passport.authenticate('login', {
		successRedirect: '/home',
		failureRedirect: '/',
		failureFlash : true  
	}));

	/* GET Registration Page */
	router.get('/register', function(req, res){
		res.render('register',{message: req.flash('message')});
	});

	/* Handle Registration POST */
	router.post('/register', passport.authenticate('register', {
		successRedirect: '/home',
		failureRedirect: '/register',
		failureFlash : true  
	}));

	/* GET Home Page */
	router.get('/home', isAuthenticated, function(req, res){
		res.render('home', { user: req.user });
	});

	/* Handle Logout */
	router.get('/signout', function(req, res) {
		req.logout();
		res.redirect('/');
	});

	return router;
}

We're using passport.authenticate() to delegate the authentication to login and register strategies when a HTTP POST is made to /login and /register routes respectively.





views/layout.jade
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css')
  body
    block content




views/index.jade
extends layout

block content
	div.container
		div.row
			div.col-sm-6.col-md-4.col-md-offset-4
				h1.text-center.login-title Sign in to our Passport app
					div.account-wall
						img(class='profile-img', src='https://lh5.googleusercontent.com/-b0-k99FZlyE/AAAAAAAAAAI/AAAAAAAAAAA/eu7opA4byxI/photo.jpg?sz=120')
						form(class='form-signin', action='/login', method='POST')
							input(type='text', name='username' class='form-control', placeholder='Email',required, autofocus)
							input(type='password', name='password' class='form-control', placeholder='Password', required)
							button(class='btn btn-lg btn-primary btn-block', type='submit') Sign in
							span.clearfix
					a(href='/signup', class='text-center new-account') Create an account
					#message
					if message
						h1.text-center.error-message #{message}



SignIn.png

Click "Create an account":

register.png

Click "Register":

home.png

Click "Sign Out":

SignInToPassport.png

If we try a user that's already been created:

AlreadyExists.png

Source available at https://github.com/epic-math/NodeJS-MEAN.




Refs

Here is the list of references:

  1. User Authentication With Passport and Express 4 - B








Node.JS

  • Node.js
  • MEAN Stack : MongoDB, Express.js, AngularJS, Node.js
  • MEAN Stack Tutorial : Express.js with Jade template
  • Building REST API with Node and MongoDB
  • Nginx reverse proxy to a node application server managed by PM2
  • Jade Bootstrap sample page with Mixins
  • Real-time polls application I - Express, Jade template, and AngularJS modules/directives
  • Real-time polls application II - AngularJS partial HTML templates & style.css
  • Node ToDo List App with Mongodb
  • Node ToDo List App with Mongodb - II (more Angular)
  • Authentication with Passport
  • Authentication with Passport 2
  • Authentication with Passport 3 (Facebook / Twitter Login)
  • React Starter Kit
  • Meteor app with React
  • MEAN Stack app on Docker containers : micro services
  • MEAN Stack app on Docker containers : micro services via docker-compose









  • Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

    YouTubeMy YouTube channel

    Sponsor Open Source development activities and free contents for everyone.

    Thank you.

    - K Hong







    Node.JS



    Node.js

    MEAN Stack : MongoDB, Express.js, AngularJS, Node.js

    MEAN Stack Tutorial : Express.js with Jade template

    Building REST API with Node and MongoDB

    Nginx reverse proxy to a node application server managed by PM2

    Jade Bootstrap sample page with Mixins

    Real-time polls application I - Express, Jade template, and AngularJS modules/directives

    Real-time polls application II - AngularJS partial HTML templates & style.css

    Node ToDo List App with Mongodb

    Node ToDo List App with Mongodb - II (more Angular)

    Authentication with Passport

    Authentication with Passport 2

    Authentication with Passport 3 (Facebook / Twitter Login)

    React Starter Kit

    Meteor app with React

    MEAN Stack app on Docker containers : micro services

    MEAN Stack app on Docker containers : micro services via docker-compose




    Sponsor Open Source development activities and free contents for everyone.

    Thank you.

    - K Hong







    AngularJS



    Introduction

    Directives I - ng-app, ng-model, and ng-bind

    Directives II - ng-show, ng-hide, and ng-disabled

    Directives III - ng-click with toggle()

    Expressions - numbers, strings, and arrays

    Binding - ng-app, ng-model, and ng-bind

    Controllers - global controllers, controller method, and external controllers

    Data Binding and Controllers (Todo App)

    Todo App with Node

    $scope - A glue between javascript (controllers) and HTML (the view)

    Tables and css

    Dependency Injection - http:fetch json & minification

    Filters - lower/uppercase, currenty, orderBy, and filter:query with http.get()

    $http - XMLHttpRequest and json file

    Module - module file and controller file

    Forms

    Routes I - introduction

    Routes II - separate url template files

    Routes III - extracting and using parameters from routes

    Routes IV - navigation between views using links

    Routes V - details page

    AngularJS template using ng-view directive : multiple views

    Nested and multi-views using UI-router, ngRoute vs UI-router

    Creating a new service using factory

    Querying into a service using find()

    angular-seed - the seed for AngularJS apps

    Token (JSON Web Token - JWT) based auth backend with NodeJS

    Token (JSON Web Token - JWT) based auth frontend with AngularJS

    Twitter Bootstrap

    Online resources - List of samples using AngularJS (Already launched sites and projects)

    Meteor Angular App with MongoDB (Part I)

    Meteor Angular App with MongoDB (Part II - Angular talks with MongoDB)

    Meteor Angular App with MongoDB (Part III - Facebook / Twitter / Google logins)

    Scala/Java Play app with Angular

    Laravel 5 / Angular Auth using JSON Web Token (JWT) - Prod

    Scala/Java Play app with Angular







    Docker & K8s



    Docker install on Amazon Linux AMI

    Docker install on EC2 Ubuntu 14.04

    Docker container vs Virtual Machine

    Docker install on Ubuntu 14.04

    Docker Hello World Application

    Nginx image - share/copy files, Dockerfile

    Working with Docker images : brief introduction

    Docker image and container via docker commands (search, pull, run, ps, restart, attach, and rm)

    More on docker run command (docker run -it, docker run --rm, etc.)

    Docker Networks - Bridge Driver Network

    Docker Persistent Storage

    File sharing between host and container (docker run -d -p -v)

    Linking containers and volume for datastore

    Dockerfile - Build Docker images automatically I - FROM, MAINTAINER, and build context

    Dockerfile - Build Docker images automatically II - revisiting FROM, MAINTAINER, build context, and caching

    Dockerfile - Build Docker images automatically III - RUN

    Dockerfile - Build Docker images automatically IV - CMD

    Dockerfile - Build Docker images automatically V - WORKDIR, ENV, ADD, and ENTRYPOINT

    Docker - Apache Tomcat

    Docker - NodeJS

    Docker - NodeJS with hostname

    Docker Compose - NodeJS with MongoDB

    Docker - Prometheus and Grafana with Docker-compose

    Docker - StatsD/Graphite/Grafana

    Docker - Deploying a Java EE JBoss/WildFly Application on AWS Elastic Beanstalk Using Docker Containers

    Docker : NodeJS with GCP Kubernetes Engine

    Docker : Jenkins Multibranch Pipeline with Jenkinsfile and Github

    Docker : Jenkins Master and Slave

    Docker - ELK : ElasticSearch, Logstash, and Kibana

    Docker - ELK 7.6 : Elasticsearch on Centos 7 Docker - ELK 7.6 : Filebeat on Centos 7

    Docker - ELK 7.6 : Logstash on Centos 7

    Docker - ELK 7.6 : Kibana on Centos 7 Part 1

    Docker - ELK 7.6 : Kibana on Centos 7 Part 2

    Docker - ELK 7.6 : Elastic Stack with Docker Compose

    Docker - Deploy Elastic Cloud on Kubernetes (ECK) via Elasticsearch operator on minikube

    Docker - Deploy Elastic Stack via Helm on minikube

    Docker Compose - A gentle introduction with WordPress

    Docker Compose - MySQL

    MEAN Stack app on Docker containers : micro services

    Docker Compose - Hashicorp's Vault and Consul Part A (install vault, unsealing, static secrets, and policies)

    Docker Compose - Hashicorp's Vault and Consul Part B (EaaS, dynamic secrets, leases, and revocation)

    Docker Compose - Hashicorp's Vault and Consul Part C (Consul)

    Docker Compose with two containers - Flask REST API service container and an Apache server container

    Docker compose : Nginx reverse proxy with multiple containers

    Docker compose : Nginx reverse proxy with multiple containers

    Docker & Kubernetes : Envoy - Getting started

    Docker & Kubernetes : Envoy - Front Proxy

    Docker & Kubernetes : Ambassador - Envoy API Gateway on Kubernetes

    Docker Packer

    Docker Cheat Sheet

    Docker Q & A

    Kubernetes Q & A - Part I

    Kubernetes Q & A - Part II

    Docker - Run a React app in a docker

    Docker - Run a React app in a docker II (snapshot app with nginx)

    Docker - NodeJS and MySQL app with React in a docker

    Docker - Step by Step NodeJS and MySQL app with React - I

    Installing LAMP via puppet on Docker

    Docker install via Puppet

    Nginx Docker install via Ansible

    Apache Hadoop CDH 5.8 Install with QuickStarts Docker

    Docker - Deploying Flask app to ECS

    Docker Compose - Deploying WordPress to AWS

    Docker - WordPress Deploy to ECS with Docker-Compose (ECS-CLI EC2 type)

    Docker - ECS Fargate

    Docker - AWS ECS service discovery with Flask and Redis

    Docker & Kubernetes: minikube version: v1.31.2, 2023

    Docker & Kubernetes 1 : minikube

    Docker & Kubernetes 2 : minikube Django with Postgres - persistent volume

    Docker & Kubernetes 3 : minikube Django with Redis and Celery

    Docker & Kubernetes 4 : Django with RDS via AWS Kops

    Docker & Kubernetes : Kops on AWS

    Docker & Kubernetes : Ingress controller on AWS with Kops

    Docker & Kubernetes : HashiCorp's Vault and Consul on minikube

    Docker & Kubernetes : HashiCorp's Vault and Consul - Auto-unseal using Transit Secrets Engine

    Docker & Kubernetes : Persistent Volumes & Persistent Volumes Claims - hostPath and annotations

    Docker & Kubernetes : Persistent Volumes - Dynamic volume provisioning

    Docker & Kubernetes : DaemonSet

    Docker & Kubernetes : Secrets

    Docker & Kubernetes : kubectl command

    Docker & Kubernetes : Assign a Kubernetes Pod to a particular node in a Kubernetes cluster

    Docker & Kubernetes : Configure a Pod to Use a ConfigMap

    AWS : EKS (Elastic Container Service for Kubernetes)

    Docker & Kubernetes : Run a React app in a minikube

    Docker & Kubernetes : Minikube install on AWS EC2

    Docker & Kubernetes : Cassandra with a StatefulSet

    Docker & Kubernetes : Terraform and AWS EKS

    Docker & Kubernetes : Pods and Service definitions

    Docker & Kubernetes : Headless service and discovering pods

    Docker & Kubernetes : Service IP and the Service Type

    Docker & Kubernetes : Kubernetes DNS with Pods and Services

    Docker & Kubernetes - Scaling and Updating application

    Docker & Kubernetes : Horizontal pod autoscaler on minikubes

    Docker & Kubernetes : NodePort vs LoadBalancer vs Ingress

    Docker & Kubernetes : Load Testing with Locust on GCP Kubernetes

    Docker & Kubernetes : From a monolithic app to micro services on GCP Kubernetes

    Docker & Kubernetes : Rolling updates

    Docker & Kubernetes : Deployments to GKE (Rolling update, Canary and Blue-green deployments)

    Docker & Kubernetes : Slack Chat Bot with NodeJS on GCP Kubernetes

    Docker & Kubernetes : Continuous Delivery with Jenkins Multibranch Pipeline for Dev, Canary, and Production Environments on GCP Kubernetes

    Docker & Kubernetes - MongoDB with StatefulSets on GCP Kubernetes Engine

    Docker & Kubernetes : Nginx Ingress Controller on minikube

    Docker & Kubernetes : Setting up Ingress with NGINX Controller on Minikube (Mac)

    Docker & Kubernetes : Nginx Ingress Controller for Dashboard service on Minikube

    Docker & Kubernetes : Nginx Ingress Controller on GCP Kubernetes

    Docker & Kubernetes : Kubernetes Ingress with AWS ALB Ingress Controller in EKS

    Docker & Kubernetes : MongoDB / MongoExpress on Minikube

    Docker & Kubernetes : Setting up a private cluster on GCP Kubernetes

    Docker & Kubernetes : Kubernetes Namespaces (default, kube-public, kube-system) and switching namespaces (kubens)

    Docker & Kubernetes : StatefulSets on minikube

    Docker & Kubernetes : StatefulSets on minikube

    Docker & Kubernetes : RBAC

    Docker & Kubernetes Service Account, RBAC, and IAM

    Docker & Kubernetes - Kubernetes Service Account, RBAC, IAM with EKS ALB, Part 1

    Docker & Kubernetes : Helm Chart

    Docker & Kubernetes : My first Helm deploy

    Docker & Kubernetes : Readiness and Liveness Probes

    Docker & Kubernetes : Helm chart repository with Github pages

    Docker & Kubernetes : Deploying WordPress and MariaDB with Ingress to Minikube using Helm Chart

    Docker & Kubernetes : Deploying WordPress and MariaDB to AWS using Helm 2 Chart

    Docker & Kubernetes : Deploying WordPress and MariaDB to AWS using Helm 3 Chart

    Docker & Kubernetes : Helm Chart for Node/Express and MySQL with Ingress

    Docker & Kubernetes : Docker_Helm_Chart_Node_Expess_MySQL_Ingress.php

    Docker & Kubernetes: Deploy Prometheus and Grafana using Helm and Prometheus Operator - Monitoring Kubernetes node resources out of the box

    Docker & Kubernetes : Deploy Prometheus and Grafana using kube-prometheus-stack Helm Chart

    Docker & Kubernetes : Istio (service mesh) sidecar proxy on GCP Kubernetes

    Docker & Kubernetes : Istio on EKS

    Docker & Kubernetes : Istio on Minikube with AWS EC2 for Bookinfo Application

    Docker & Kubernetes : Deploying .NET Core app to Kubernetes Engine and configuring its traffic managed by Istio (Part I)

    Docker & Kubernetes : Deploying .NET Core app to Kubernetes Engine and configuring its traffic managed by Istio (Part II - Prometheus, Grafana, pin a service, split traffic, and inject faults)

    Docker & Kubernetes : Helm Package Manager with MySQL on GCP Kubernetes Engine

    Docker & Kubernetes : Deploying Memcached on Kubernetes Engine

    Docker & Kubernetes : EKS Control Plane (API server) Metrics with Prometheus

    Docker & Kubernetes : Spinnaker on EKS with Halyard

    Docker & Kubernetes : Continuous Delivery Pipelines with Spinnaker and Kubernetes Engine

    Docker & Kubernetes: Multi-node Local Kubernetes cluster - Kubeadm-dind(docker-in-docker)

    Docker & Kubernetes: Multi-node Local Kubernetes cluster - Kubeadm-kind(k8s-in-docker)

    Docker & Kubernetes : nodeSelector, nodeAffinity, taints/tolerations, pod affinity and anti-affinity - Assigning Pods to Nodes

    Docker & Kubernetes : Jenkins-X on EKS

    Docker & Kubernetes : ArgoCD App of Apps with Heml on Kubernetes

    Docker & Kubernetes : ArgoCD on Kubernetes cluster

    Docker & Kubernetes : GitOps with ArgoCD for Continuous Delivery to Kubernetes clusters (minikube) - guestbook










    Contact

    BogoToBogo
    contactus@bogotobogo.com

    Follow Bogotobogo

    About Us

    contactus@bogotobogo.com

    YouTubeMy YouTube channel
    Pacific Ave, San Francisco, CA 94115

    Pacific Ave, San Francisco, CA 94115

    Copyright © 2024, bogotobogo
    Design: Web Master