Oh Snap!

Please turnoff your ad blocking mode for viewing your site content

Hit enter after type your search item

Node.js Express Session Based Authentication System Using Express-Session Cookie-Parser in MongoDB

/
/
/
127 Views

Welcome folks today in this post we will making a simple session based authentication system in node and express using the express-session and cookie parser library. And we will be using mongodb as the database for storing user information and also we will doing some schema validations using the mongoose library which will directly interact with the Mongodb. All the source code of the application will be given below. Also a step by step youtube video is also given below to follow along with the blog.

 

 

Screenshots

 

 

Requirements

 

 

In the screenshot above we have all the dependencies that are needed for this project. First of all we need express for starting our server and we also need express-session to make the session functionality inside our authentication system and also we have cookie-parser to store and retrieve the cookies stored inside the browser. And then we neeed mongoose to directly interact with the Mongodb database. And then we also need Nodemon to restart the server whenever we make any kind of changes to our application. We are using a password hashing library bcrypt to hash the passwords which are stored. We are using the body-parser to retrieve the form values which are being submitted. And lastly we are using morgan library which is famous for logging out requests inside the console.

Now after all this setup. We now have to create app.js which will be the starting point of the application. First of all we will make a simple express server at a certain port number.

 

var express = require("express");

var app = express();

// set our application port
app.set("port", 4000);

app.listen(app.get("port"), () =>
  console.log(`App started on port ${app.get("port")}`)
);

 

Now we need to define all the middleware functions including express-session and cookie-parser to prevent users from opening certain protected pages when they are not logged in.

 

var bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");
var session = require("express-session");
var morgan = require("morgan");


// set morgan to log info about our requests for development use.
app.use(morgan("dev"));

// initialize body-parser to parse incoming parameters requests to req.body
app.use(bodyParser.urlencoded({ extended: true }));

// initialize cookie-parser to allow us access the cookies stored in the browser.
app.use(cookieParser());

// initialize express-session to allow us track the logged-in user across sessions.
app.use(
  session({
    key: "user_sid",
    secret: "somerandonstuffs",
    resave: false,
    saveUninitialized: false,
    cookie: {
      expires: 600000,
    },
  })
);

// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.
// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.
app.use((req, res, next) => {
  if (req.cookies.user_sid && !req.session.user) {
    res.clearCookie("user_sid");
  }
  next();
});

// middleware function to check for logged-in users
var sessionChecker = (req, res, next) => {
  if (req.session.user && req.cookies.user_sid) {
    res.redirect("/dashboard");
  } else {
    next();
  }
};

 

So in this block of code we are including body-parser middleware and also morgan middleware setting it up. And then we are initializing expression-session and cookie-parser middlewares. In express-session we are passing some options such as the expiry time for the session.How much time does the session last inside the user browser. And there are two more functions one checks if the user is currently logged in or not. If it is logged in then it redirects the user to dashboard page otherwise not. And the second one if the user is logged out then it deletes the cookies inside the user browser.

 

// route for Home-Page
app.get("/", sessionChecker, (req, res) => {
  res.redirect("/login");
});

 

And now in the next step we are using both the middleware functions which we have defined earlier and now if we have a get request to the login page and then it checks if the user is logged in or not by sessionChecker function if it is not then we redirect the user to the login page.

Now at this moment of time we will define the views for our application. So just create a new folder public inside your root directory and then inside it create login.html file and copy paste the following static html code and we are using some bootstrap to style our html content.

READ  How to make a Simple Keylogger in Javascript

 

<html>
    <head>
        <title>Login Here</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body class="container">
        <div class="page-header">
            <h1>Simple Auth-System</h1>
        </div>

        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                        <li><a href="/">Home</a></li>
                        <li><a href="/signup">Sign Up</a></li>
                        <li><a href="/dashboard">Dashboard</a></li>
                    </ul>

                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="/login">Log In</a></li>
                        <li><a href="/logout">Log Out</a></li>
                    </ul>
                </div><!-- /.navbar-collapse -->
            </div><!-- /.container-fluid -->
        </nav>

        <div class="container row">
            <div class="jumbotron col-sm-4 pull-center">
                <form autocomplete="off" action="/login" method="post">
                    <div class="form-group">
                        <label>Username:</label>
                        <input class="form-control" required type="text" name="username"/>
                    </div>
                    <div class="form-group">
                        <label>Password:</label>
                        <input class="form-control" required type="password" name="password"/>
                    </div>
                    <div class="form-group">
                        <input class="btn btn-primary" type="submit" value="Log In"/>
                    </div>
                </form>                  
            </div>          
        </div>
    </body>
</html>

 

Now if you open app and go to the home route then it will redirect to the login page as you are not logged in. It will detect automatically because we have defined the middleware function of express-session.

 

app
  .route("/login")
  .get(sessionChecker, (req, res) => {
    res.sendFile(__dirname + "/public/login.html");
  })

 

So this is the actual route for the login page when you hit it again we check in between whether user is already logged in or not by passing the sessionChecker middleware function. If it is not then we simply load the static login.html page which resides inside the public directory of our application.

Now we will register users inside our application. If you open the login page you will see various links point to varioius routes. One route we take is the signup route. If you click the signup link it will take you to signup.html so we need to create a simple get route for that inside the express app.

 

app
  .route("/signup")
  .get(sessionChecker, (req, res) => {
    res.sendFile(__dirname + "/public/signup.html");
  })

 

Now you can see this is the simple get route to the /signup and then we are passing middleware function and also we are loading the signup.html page.

Just create signup.html page inside our public directory of application. And copy paste the following static html code.

 

<html>
    <head>
        <title>Login Here</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body class="container">
        <div class="page-header">
            <h1>Simple Auth-System</h1>
        </div>

        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                        <li><a href="/">Home</a></li>
                        <li><a href="/signup">Sign Up</a></li>
                        <li><a href="/dashboard">Dashboard</a></li>
                    </ul>

                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="/login">Log In</a></li>
                        <li><a href="/logout">Log Out</a></li>
                    </ul>
                </div><!-- /.navbar-collapse -->
            </div><!-- /.container-fluid -->
        </nav>

        <div class="container row">
            <div class="jumbotron col-sm-4 pull-center">
                <form autocomplete="off" action="/signup" method="post">
                    <div class="form-group">
                        <label>Username:</label>
                        <input class="form-control" required type="text" name="username"/>
                    </div>
                    <div class="form-group">
                        <label>Email:</label>
                        <input class="form-control" required type="email" name="email"/>
                    </div>    
                    <div class="form-group">
                        <label>Password:</label>
                        <input class="form-control" required type="password" name="password"/>
                    </div>
                    <div class="form-group">
                        <input class="btn btn-primary" type="submit" value="Sign Up"/>
                    </div>
                </form>                  
            </div>          
        </div>
    </body>
</html>

 

And now before registering our users through this form inside the signup.html. First of all we need to define our model for our database and we need to connect to the database.

For that create a new models directory inside our root of the application and create a User.js file which will be the actual model for our application holding all the schema relating information of the application.

 

const mongoose = require('mongoose')
const bcrypt = require('bcrypt')

mongoose.connect("mongodb://localhost:27017/userDB",{
    useNewUrlParser:true,
    useUnifiedTopology:true
})

const userSchema = mongoose.Schema({
    username:{
        type:String,
        unique:true,
        required: true
    },
    email:{
        type:String,
        unique:true,
        required:true
    },
    password:{
        type:String,
        required:true
    }
})

userSchema.pre("save", function(next) {
    if(!this.isModified("password")) {
        return next();
    }
    this.password = bcrypt.hashSync(this.password, 10);
    next();
});

userSchema.methods.comparePassword = function(plaintext, callback) {
    return callback(null, bcrypt.compareSync(plaintext, this.password));
};

const userModel = mongoose.model('user',userSchema)

module.exports = userModel

 

Here in this block of code we are doing some serious things for our application. First of all we are importing mongoose and bcrypt dependencies right at the top of the application. And then we are using mongoose to connect to the database So we are using the MongoDB community edition which is a desktop GUI Application for MongoDB. Our database is userDB. You can create your database and plug that name inside the connection URL and rest of the things will remain constant.

And then after that we are defining the schema of our application holding three fields username, password and email fields and also we are providing some additional fields to username and email such as type parameter set to String as they are all Strings and additional parameter of Unique to true is simply given to make these fields unique and to prevent users from registering two records with same username and email address. This unique field is provided by mongoose library. And lastly we set required to true we want all the three fields to be entered by the user.

READ  Electron Drag and Drop File Example with Editing

And then we are defining two custom functions on our schema first function simply hash the password which is provided by the user at the time of signup. This function will automatically execute at the time of creating the record because we have put this function inside a special event you can see we are binding it on userSchema variable and we are using the pre function simply execute this function just before the records are insierted to the database.

And also our second function which will compare the password with the actual correct hash by using bcrypt library function. This is highly useful at the time of login.

And after that we are defining the model of the application passing the actual schema of the application.

And then we are simply exporting the model of the application by using module.exports so that we can use this model in different files of the application.

Now we need to simply include the model file inside our app.js file.

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

 

So after this we will process the signup form by writing the post request which will be executed when you submit the signup form.

app
  .route("/signup")
  .get(sessionChecker, (req, res) => {
    res.sendFile(__dirname + "/public/signup.html");
  })
  .post((req, res) => {

    var user = new User({
      username: req.body.username,
      email: req.body.email,
      password:req.body.password,
    });
    user.save((err, docs) => {
      if (err) {
        res.redirect("/signup");
      } else {
          console.log(docs)
        req.session.user = docs;
        res.redirect("/dashboard");
      }
    });
  });

 

So now inside this block of code we are getting the information which the user entered through req.body and then we are creating a new user passing the required information such as username , email and password. Here we are passing the plain password and then at the time of creation just before that hashing function executes it creates the hash of the password and then it inserts the hashed password to the database. Here we check if any kind of error takes place then we are redirecting the user back to the signup route and if no error takes place then we are setting the session variable to the docs. And then redirecting the user to the dashboard route.

 

 

So as you can see these details are inserted into the mongodb database. And the password is securely hashed by bcrypt library.

So now we can make the dashboard.html file which will hold a welcome message for the user once the user signups or logins. Now create this file inside our public folder

 

<html>
    <head>
        <title>Login Here</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body class="container">
        <div class="page-header">
            <h1>Simple Auth-System</h1>
        </div>

        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                        <li><a href="/">Home</a></li>
                        <li><a href="/signup">Sign Up</a></li>
                        <li><a href="/dashboard">Dashboard</a></li>
                    </ul>

                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="/login">Log In</a></li>
                        <li><a href="/logout">Log Out</a></li>
                    </ul>
                </div><!-- /.navbar-collapse -->
            </div><!-- /.container-fluid -->
        </nav>

        <div class="container row">
           <h1>Hi, Welcome to your Dashboard</h1>
        </div>
    </body>
</html>

 

And in similar fashion we will implement the login functionality as well. We will process the post request on the login route.

 

// route for user Login
app
  .route("/login")
  .get(sessionChecker, (req, res) => {
    res.sendFile(__dirname + "/public/login.html");
  })
  .post(async (req, res) => {
    var username = req.body.username,
      password = req.body.password;

      try {
        var user = await User.findOne({ username: username }).exec();
        if(!user) {
            res.redirect("/login");
        }
        user.comparePassword(password, (error, match) => {
            if(!match) {
              res.redirect("/login");
            }
        });
        req.session.user = user;
        res.redirect("/dashboard");
    } catch (error) {
      console.log(error)
    }
  });

 

So now inside this block of code we are getting the user information such as username and password and then we are checking the database with the desired username and then we are getting the actual record with that username. If the record doesn’t exist then we redirect the user to login route. And in the next check we are comparing the password which is passed by the user and then we are using the custom function which we have defined and we are using it. And if the password doesn’t match then we redirect the user to the login page. And if all things went right then we set the session variable to the user data and also we redirect the user back to the dashboard page.

READ  Build Youtube Ultimate SEO Tool Using Youtube Data API V3

 

// route for user's dashboard
app.get("/dashboard", (req, res) => {
  if (req.session.user && req.cookies.user_sid) {
    res.sendFile(__dirname + "/public/dashboard.html");
  } else {
    res.redirect("/login");
  }
});

 

So now inside this block of code we are writing the code to the /dashboard route so whenever the user goes to the dashboard route we are checking if the user session is set and also if the cookie is also set then only we load the dashboard page. Else we redirect the user back to the login route.

And now lastly we simply will be writing the route to logout the user from the dashboard page so that the user can’t go to dashboard once they are logged out from the application.

 

// route for user logout
app.get("/logout", (req, res) => {
  if (req.session.user && req.cookies.user_sid) {
    res.clearCookie("user_sid");
    res.redirect("/");
  } else {
    res.redirect("/login");
  }
});

 

In this block of code we are writing the /logout route so whenever someone goes to this route for logging out first of all we check if the user session exist and also the cookie exist then we clear out the session and also clear out the cookies permanently associated with the user And then we redirect the user to the homepage. Else we redirect the user back to the login page.

And lastly we need to write a simple route to handle the 404 route for our application. So whenever the user goes to a wrong page then this route will be useful.

 

// route for handling 404 requests(unavailable routes)
app.use(function (req, res, next) {
  res.status(404).send("Sorry can't find that!");
});

 

Full App.js Code

 

var express = require("express");
var bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");
var session = require("express-session");
var morgan = require("morgan");
var User = require("./models/User");

var app = express();

// set our application port
app.set("port", 4000);

// set morgan to log info about our requests for development use.
app.use(morgan("dev"));

// initialize body-parser to parse incoming parameters requests to req.body
app.use(bodyParser.urlencoded({ extended: true }));

// initialize cookie-parser to allow us access the cookies stored in the browser.
app.use(cookieParser());

// initialize express-session to allow us track the logged-in user across sessions.
app.use(
  session({
    key: "user_sid",
    secret: "somerandonstuffs",
    resave: false,
    saveUninitialized: false,
    cookie: {
      expires: 600000,
    },
  })
);

// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.
// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.
app.use((req, res, next) => {
  if (req.cookies.user_sid && !req.session.user) {
    res.clearCookie("user_sid");
  }
  next();
});

// middleware function to check for logged-in users
var sessionChecker = (req, res, next) => {
  if (req.session.user && req.cookies.user_sid) {
    res.redirect("/dashboard");
  } else {
    next();
  }
};

// route for Home-Page
app.get("/", sessionChecker, (req, res) => {
  res.redirect("/login");
});

// route for user signup
app
  .route("/signup")
  .get(sessionChecker, (req, res) => {
    res.sendFile(__dirname + "/public/signup.html");
  })
  .post((req, res) => {

    var user = new User({
      username: req.body.username,
      email: req.body.email,
      password:req.body.password,
    });
    user.save((err, docs) => {
      if (err) {
        res.redirect("/signup");
      } else {
          console.log(docs)
        req.session.user = docs;
        res.redirect("/dashboard");
      }
    });
  });

// route for user Login
app
  .route("/login")
  .get(sessionChecker, (req, res) => {
    res.sendFile(__dirname + "/public/login.html");
  })
  .post(async (req, res) => {
    var username = req.body.username,
      password = req.body.password;

      try {
        var user = await User.findOne({ username: username }).exec();
        if(!user) {
            res.redirect("/login");
        }
        user.comparePassword(password, (error, match) => {
            if(!match) {
              res.redirect("/login");
            }
        });
        req.session.user = user;
        res.redirect("/dashboard");
    } catch (error) {
      console.log(error)
    }
  });

// route for user's dashboard
app.get("/dashboard", (req, res) => {
  if (req.session.user && req.cookies.user_sid) {
    res.sendFile(__dirname + "/public/dashboard.html");
  } else {
    res.redirect("/login");
  }
});

// route for user logout
app.get("/logout", (req, res) => {
  if (req.session.user && req.cookies.user_sid) {
    res.clearCookie("user_sid");
    res.redirect("/");
  } else {
    res.redirect("/login");
  }
});

// route for handling 404 requests(unavailable routes)
app.use(function (req, res, next) {
  res.status(404).send("Sorry can't find that!");
});

// start the express server
app.listen(app.get("port"), () =>
  console.log(`App started on port ${app.get("port")}`)
);

 

DOWNLOAD SOURCE CODE

 

Leave a Comment

Your email address will not be published. Required fields are marked *

This div height required for enabling the sticky sidebar
Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views : Ad Clicks : Ad Views :