Node.js User Authentication with Bcrypt

In this lesson, we will be allowing users to create accounts, disguising their passwords to prevent hackers from stealing them, saving the accounts in a MongoDB database, and allowing users to log in with their account info.

In your project directory in Terminal, use this command to create a package.json file for your project

npm init -y

Any project that is using Node.js needs a package.json file. The file contains the project’s dependencies, source control information, and specific metadata.

Now install all the packages that our project will need using npm.

npm i express body-parser ejs mongoose bcrypt

I will show you how to set up the app.js file, but you’ll have to design the ejs (or html) and css files on your own.

In general, though, you’ll want to include something like this in your login & signup files:

<form action="/login" method="POST">
   <div class="form-group">
       <label for="email">Email</label>
       <input type="email" class="form-control" name="username">
   </div>
   <div class="form-group">
        <label for="password">Password</label>
        <input type="password" class="form-control" name="password">
   </div>
   <button type="submit" class="btn btn-dark">Login</button>
</form>

You will need a form that has an action parameter that posts to a route. You will take the user’s input using named input tags that can be referenced in the server file.

In your app.js file, require all the packages we installed earlier. Also create a saltRounds variable and set it to 10. We will use it later to salt our passwords.

const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const saltRounds = 10;

More standard setup:

const app = express();

app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
  extended: true
}));

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

Create the User Model in MongoDB:

const userSchema = new mongoose.Schema ({
  email: String,
  password: String
});


const User = new mongoose.model("User", userSchema);

Set up the get routes so users can get to the different pages:

app.get("/", function(req, res){
  res.render("home");
});

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

app.get("/register", function(req, res){
  res.render("register");
});

Handle users entering their information into the login and register forms:

Posting to the Register Route

As you can see, we are using the bcrypt hash function. The function takes in the password given by the user in the request, the number of salt rounds (defined above), or times we want our password to be salted , and a callback function that can either return an error or the hashed (encrypted) password.

A new user based on our Mongo User Model is created using the username from the request and the encrypted password. Then, that user is saved into the MongoDB. If successful, the server will navigate the user to pages that require authentication.

app.post("/register", function(req, res){
  bcrypt.hash(req.body.password, saltRounds, function(err, hash) {
    const newUser =  new User({
      email: req.body.username,
      password: hash
    });
    newUser.save(function(err){
      if (err) {
        console.log(err);
      } else {
        res.render("secrets");
      }
    });
  });

});
Posting to the Login Route

First, using the findOne function, we see if there are any emails in our database that match the one inputted by the user. This findOne function can return either an error or a found user/ matching user. If a user is found for the inputted email, bcrypt will proceed to compare the inputted password with the password for the email in the database. If it’s another match (result === true), the server will navigate the user to pages that require authentication.

app.post("/login", function(req, res){
  const username = req.body.username;
  const password = req.body.password;

  User.findOne({email: username}, function(err, foundUser){
    if (err) {
      console.log(err);
    } else {
      if (foundUser) {
        bcrypt.compare(password, foundUser.password, function(err, result) {
          if (result === true) {
            res.render("secrets");
          }
        });
      }
    }
  });
});

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s