ExpressJS - Authentication



Authentication is a process in which the credentials provided are compared to those on file in a database of authorized users' information on a local operating system or within an authentication server. If the credentials match, the process is completed and the user is granted authorization for access.

For us to create an authentication system, we will need to create a sign up page and a user-password store. The following code creates an account for us and stores it in memory. This is just for the purpose of demo; it is recommended that a persistent storage (database or files) is always used to store user information.

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer(); 
var session = require('express-session');
var cookieParser = require('cookie-parser');

app.set('view engine', 'pug');
app.set('views','./views');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); 
app.use(upload.array());
app.use(cookieParser());
app.use(session({secret: "Your secret key"}));

var Users = [];

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

app.post('/signup', function(req, res){
   if(!req.body.id || !req.body.password){
      res.status("400");
      res.send("Invalid details!");
   } else {
      Users.filter(function(user){
         if(user.id === req.body.id){
            res.render('signup', {
               message: "User Already Exists! Login or choose another user id"});
         }
      });
      var newUser = {id: req.body.id, password: req.body.password};
      Users.push(newUser);
      req.session.user = newUser;
      res.redirect('/protected_page');
   }
});

app.listen(3000);

Now for the signup form, create a new view called signup.jade.

SIGNUP.JADE

html
   head
      title Signup
   body
      if(message)
         h4 #{message}
         form(action = "/signup" method = "POST")
         input(name = "id" type = "text" required placeholder = "User ID")
         input(name = "password" type = "password" required placeholder = "Password")
         button(type = "Submit") Sign me up!

Check if this page loads by visiting localhost:3000/signup.

Signup form

We have set the required attribute for both fields, so HTML5 enabled browsers will not let us submit this form until we provide both id and password. If someone tries to register using a curl request without a User ID or Password, an error will be displayed. Create a new file called protected_page.pug in views with the following content −

html
   head
      title Protected page
   body
      div Hey #{id}, How are you doing today?
      div Want to log out?
      div Logout

This page should only be visible if the user has just signed up or logged in. Let us now define its route and also routes to log in and log out −

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer(); 
var session = require('express-session');
var cookieParser = require('cookie-parser');

app.set('view engine', 'pug');
app.set('views','./views');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); 
app.use(upload.array());
app.use(cookieParser());
app.use(session({secret: "Your secret key"}));

var Users = [];

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

app.post('/signup', function(req, res){
   if(!req.body.id || !req.body.password){
      res.status("400");
      res.send("Invalid details!");
   } else {
      Users.filter(function(user){
         if(user.id === req.body.id){
            res.render('signup', {
               message: "User Already Exists! Login or choose another user id"});
         }
      });
      var newUser = {id: req.body.id, password: req.body.password};
      Users.push(newUser);
      req.session.user = newUser;
      res.redirect('/protected_page');
   }
});
function checkSignIn(req, res){
   if(req.session.user){
      next();     //If session exists, proceed to page
   } else {
      var err = new Error("Not logged in!");
      console.log(req.session.user);
      next(err);  //Error, trying to access unauthorized page!
   }
}
app.get('/protected_page', checkSignIn, function(req, res){
   res.render('protected_page', {id: req.session.user.id})
});

app.get('/login', function(req, res){
   res.render('login');
});

app.post('/login', function(req, res){
   console.log(Users);
   if(!req.body.id || !req.body.password){
      res.render('login', {message: "Please enter both id and password"});
   } else {
      Users.filter(function(user){
         if(user.id === req.body.id && user.password === req.body.password){
            req.session.user = user;
            res.redirect('/protected_page');
         }
      });
      res.render('login', {message: "Invalid credentials!"});
   }
});

app.get('/logout', function(req, res){
   req.session.destroy(function(){
      console.log("user logged out.")
   });
   res.redirect('/login');
});

app.use('/protected_page', function(err, req, res, next){
console.log(err);
   //User should be authenticated! Redirect him to log in.
   res.redirect('/login');
});

app.listen(3000);

We have created a middleware function checkSignIn to check if the user is signed in. The protected_page uses this function. To log the user out, we destroy the session.

Let us now create the login page. Name the view as login.pug and enter the contents −

html
   head
      title Signup
   body
      if(message)
         h4 #{message}
         form(action = "/login" method = "POST")
         input(name = "id" type = "text" required placeholder = "User ID")
         input(name = "password" type = "password" required placeholder = "Password")
         button(type = "Submit") Log in

Our simple authentication application is now complete; let us now test the application. Run the app using nodemon index.js, and proceed to localhost:3000/signup.

Enter a Username and a password and click sign up. You will be redirected to the protected_page if details are valid/unique −

Protected page

Now log out of the app. This will redirect us to the login page −

Auth login

This route is protected such that if an unauthenticated person tries to visit it, he will be redirected to our login page. This was all about basic user authentication. It is always recommended that we use a persistent session system and use hashes for password transport. There are much better ways to authenticate users now, leveraging JSON tokens.

Advertisements