Login & Registration Application Using NodeJS Express and MySQL

CategoryWed Designing
LanguageNodeJS
DatabaseMySQL Database
Author Tutor Joes

The purpose of this article is to demonstrate to learn how to create a login form using Node.js and MySQL.

What is NodeJS?

Node.js is written in C, C++, and JavaScript. NodeJS is an open-source JavaScript tool built on Google Chrome's JavaScript Engine.It also cross-platform runtime environment for executing JavaScript code outside a browser.

Node.js - Express Framework

Express is a minimal and flexible Node.js web application framework that provides a robust set of features to develop web and mobile applications. It facilitates the rapid development of Node based Web applications. Following are some of the core features of Express framework.

  • Allows to set up middle wares to respond to HTTP Requests.
  • Defines a routing table which is used to perform different actions based on HTTP Method and URL.
  • Allows to dynamically render HTML Pages based on passing arguments to templates.

Source Code

Template Files

style.css
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;500&display=swap');
*{
  margin: 0;
  padding: 0;
  outline: none;
  box-sizing: border-box;
  font-family: 'Noto Sans', sans-serif;
}
body{
  height: 100vh;
  width: 100%;
  background:#5199E4;
}

.container,
.container-fluid
{
  position: absolute;
  top:50%;
  left: 50%;
  transform: translate(-50%,-50%);
  display: block;
  background: #fff;
  width: 410px;
  padding: 30px;
  box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;
}

.container .text{
  font-size: 35px;
  font-weight: 400;
  text-align: center;
  color:#5199E4;
}

.container form{
margin-top: -20px;
}

.container form .data{
  height: 45px;
  width: 100%;
  margin: 40px 0;
}

form .data label{
  font-size: 18px;
}


form .data input{
  height: 100%;
  width: 100%;
  padding-left: 10px;
  font-size: 17px;
  border: 1px solid silver;
}

form .data input:focus{
  border-color: #5199E4;
  border-bottom-width: 2px;
}


form .forgot-pass{
  margin-top: -8px;
}
form .forgot-pass a{
  color: #5199E4;
  text-decoration: none;
}
form .forgot-pass a:hover{
  text-decoration: underline;
}

form .btn{
  margin: 30px 0;
  height: 45px;
  width: 100%;
}

form .btn button{
  height: 100%;
  width: 100%;
  background: none;
  border: none;
  color: #fff; 
   background:#5199E4;
   font-size: 18px;
   font-weight: 500;
   text-transform: uppercase;
   letter-spacing: 1px;
   cursor: pointer;
}

form .signup-link{
  text-align: center;
}

form .signup-link a{
  color: #5199E4;
  text-decoration: none;
}
form .signup-link a:hover{
  text-decoration: underline;
}
   

.container-fluid{
  width: 600px;
  display: flex;
  flex-direction: column;
  align-items: center
}

nav{
  width: 100%; 
  height:50px;
  background:white;
  padding: 0px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

nav .logo{
  font-weight:500;
  font-size: 18px;
  color:#34495e;
}

nav .menu a{
  margin:10px 10px ;
  text-decoration: none;
  font-size:18px;
  color: #5199E4;
}

nav .menu a:hover{
  text-decoration: underline;
}


.container-fluid h2,.container-fluid h3{
  font-weight: 400;
}

.container-fluid img{
  width: 200px;
}
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Node.js Login System With MySQL</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="container">
      <div class="text">User Login</div>
      <form action="#">
        <div class="data">
          <label for="email">Email</label>
          <input type="email" name="email" id="email" />
        </div>
        <div class="data">
          <label for="password">Password</label>
          <input type="password" name="password" id="password" />
        </div>
        <div class="forgot-pass">
          <a href="#">Forgot Password?</a>
        </div>
        <div class="btn">
          <button type="submit">login</button>
        </div>
        <div class="signup-link">
          Not a member? <a href="register.html">Signup now</a>
        </div>
      </form>
    </div>
  </body>
</html>
register.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Node.js Login System With MySQL</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="container">
      <div class="text">Registration</div>
      <form action="#">
        <div class="data">
          <label for="name">Full Name</label>
          <input type="text" name="name" id="name" />
        </div>
        <div class="data">
          <label for="email">Email</label>
          <input type="email" name="email" id="email" />
        </div>
        <div class="data">
          <label for="password">Password</label>
          <input type="password" name="password" id="password" />
        </div>
        <div class="data">
          <label for="confirm_password">Confirm Password</label>
          <input type="password" name="confirm_password" id="password" />
        </div>

        <div class="btn">
          <button type="submit">Register</button>
        </div>
        <div class="signup-link">
          Already a member ? <a href="index.html">Login now</a>
        </div>
      </form>
    </div>
  </body>
</html>
home.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Node.js Login System With MySQL</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <nav>
      <div class="logo">Tutor Joes</div>
      <div class="menu">
        <a href="home.html">Home</a>
        <a href="register.html">Register</a>
        <a href="index.html">Login</a>
        <a href="profile.html">Profile</a>
        <a href="#">Logout</a>
      </div>
    </nav>

    <div class="container-fluid">
      <h2>Home Page</h2>
    </div>
  </body>
</html>
profile.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Node.js Login System With MySQL</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <nav>
      <div class="logo">Tutor Joes</div>
      <div class="menu">
        <a href="home.html">Home</a>
        <a href="register.html">Register</a>
        <a href="index.html">Login</a>
        <a href="profile.html">Profile</a>
        <a href="#">Logout</a>
      </div>
    </nav>

    <div class="container-fluid">
      <h2>User Profile</h2>
      <img src="profile.png" />
      <h3>Name : User Full Name</h3>
      <h3>Email : User Email</h3>
    </div>
  </body>
</html>

NodeJS files


package.json
{
  "name": "login_system",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bcryptjs": "^2.4.3",
    "cookie-parser": "^1.4.6",
    "dotenv": "^16.0.1",
    "express": "^4.18.1",
    "hbs": "^4.2.0",
    "jsonwebtoken": "^8.5.1",
    "mysql": "^2.18.1",
    "nodemon": "^2.0.16"
  }
}
.env
DATABASE=login_crud
DATABASE_HOST=localhost
DATABASE_USER=root
DATABASE_PASS=root
JWT_SECRET=1234
JWT_EXPIRES_IN=90d
JWT_COOKIE_EXPIRES=90
app.js
const express = require("express");
const mysql = require("mysql");
const doenv = require("dotenv");
const path = require("path");
const hbs = require("hbs");
const cookieParser = require("cookie-parser");

const app = express();

doenv.config({
  path: "./.env",
});
const db = mysql.createConnection({
  host: process.env.DATABASE_HOST,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASS,
  database: process.env.DATABASE,
});

db.connect((err) => {
  if (err) {
    console.log(err);
  } else {
    console.log("MySQL Connection Success");
  }
});
app.use(cookieParser());
app.use(express.urlencoded({ extended: false }));

//console.log(__dirname);
const location = path.join(__dirname, "./public");
app.use(express.static(location));
app.set("view engine", "hbs");

const partialsPath = path.join(__dirname, "./views/partials");
hbs.registerPartials(partialsPath);

app.use("/", require("./routes/pages"));
app.use("/auth", require("./routes/auth"));

app.listen(5000, () => {
  console.log("Server Started @ Port 5000");
});
pages.js
const express = require("express");
const router = express.Router();
const userContoller = require("../controllers/users");
router.get(["/", "/login"], (req, res) => {
  //res.send("<h1>Hello Tutor Joes Salem</h1>");
  res.render("login");
});

router.get("/register", (req, res) => {
  res.render("register");
});

router.get("/profile", userContoller.isLoggedIn, (req, res) => {
  if (req.user) {
    res.render("profile", { user: req.user });
  } else {
    res.redirect("/login");
  }
});
router.get("/home", userContoller.isLoggedIn, (req, res) => {
  //console.log(req.name);
  if (req.user) {
    res.render("home", { user: req.user });
  } else {
    res.redirect("/login");
  }
});

module.exports = router;
auth.hbs
const express = require("express");
const userController = require("../controllers/users");
const router = express.Router();

router.post("/register", userController.register);
router.post("/login", userController.login);
router.get("/logout", userController.logout);
module.exports = router;
users.js
const mysql = require("mysql");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { promisify } = require("util");

const db = mysql.createConnection({
  host: process.env.DATABASE_HOST,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASS,
  database: process.env.DATABASE,
});

exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;
    if (!email || !password) {
      return res.status(400).render("login", {
        msg: "Please Enter Your Email and Password",
        msg_type: "error",
      });
    }

    db.query(
      "select * from users where email=?",
      [email],
      async (error, result) => {
        console.log(result);
        if (result.length <= 0) {
          return res.status(401).render("login", {
            msg: "Please Enter Your Email and Password",
            msg_type: "error",
          });
        } else {
          if (!(await bcrypt.compare(password, result[0].PASS))) {
            return res.status(401).render("login", {
              msg: "Please Enter Your Email and Password",
              msg_type: "error",
            });
          } else {
            const id = result[0].ID;
            const token = jwt.sign({ id: id }, process.env.JWT_SECRET, {
              expiresIn: process.env.JWT_EXPIRES_IN,
            });
            console.log("The Token is " + token);
            const cookieOptions = {
              expires: new Date(
                Date.now() +
                  process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
              ),
              httpOnly: true,
            };
            res.cookie("joes", token, cookieOptions);
            res.status(200).redirect("/home");
          }
        }
      }
    );
  } catch (error) {
    console.log(error);
  }
};
exports.register = (req, res) => {
  console.log(req.body);
  /*
  const name = req.body.name;
  const email = req.body.email;
  const password = req.body.password;
  const confirm_password = req.body.confirm_password;
  console.log(name);
  console.log(email);
    //res.send("Form Submitted");
  */
  const { name, email, password, confirm_password } = req.body;
  db.query(
    "select email from users where email=?",
    [email],
    async (error, result) => {
      if (error) {
        confirm.log(error);
      }

      if (result.length > 0) {
        return res.render("register", {
          msg: "Email id already Taken",
          msg_type: "error",
        });
      } else if (password !== confirm_password) {
        return res.render("register", {
          msg: "Password do not match",
          msg_type: "error",
        });
      }
      let hashedPassword = await bcrypt.hash(password, 8);
      //console.log(hashedPassword);

      db.query(
        "insert into users set ?",
        { name: name, email: email, pass: hashedPassword },
        (error, result) => {
          if (error) {
            console.log(error);
          } else {
            //console.log(result);
            return res.render("register", {
              msg: "User Registration Success",
              msg_type: "good",
            });
          }
        }
      );
    }
  );
};

exports.isLoggedIn = async (req, res, next) => {
  //req.name = "Check Login....";
  //console.log(req.cookies);
  if (req.cookies.joes) {
    try {
      const decode = await promisify(jwt.verify)(
        req.cookies.joes,
        process.env.JWT_SECRET
      );
      //console.log(decode);
      db.query(
        "select * from users where id=?",
        [decode.id],
        (err, results) => {
          //console.log(results);
          if (!results) {
            return next();
          }
          req.user = results[0];
          return next();
        }
      );
    } catch (error) {
      console.log(error);
      return next();
    }
  } else {
    next();
  }
};

exports.logout = async (req, res) => {
  res.cookie("joes", "logout", {
    expires: new Date(Date.now() + 2 * 1000),
    httpOnly: true,
  });
  res.status(200).redirect("/");
};
index.hbs
<!DOCTYPE html>
<html lang="en">
   {{> header   }}
  <body>
     {{> navbar   }}
    <div class="container">
      <div class="text">User Login</div>
        {{#if msg}}
      <p class="{{msg_type}}">{{msg}}</p>
      {{/if}}
      <form action="/auth/login" method="post">
        <div class="data">
          <label for="email">Email</label>
          <input type="email" name="email" id="email" />
        </div>
        <div class="data">
          <label for="password">Password</label>
          <input type="password" name="password" id="password" />
        </div>
        <div class="forgot-pass">
          <a href="#">Forgot Password?</a>
        </div>
        <div class="btn">
          <button type="submit">login</button>
        </div>
        <div class="signup-link">
          Not a member? <a href="/register">Signup now</a>
        </div>
      </form>
    </div>
  </body>
</html>
register.hbs
<!DOCTYPE html>
<html lang="en">
    {{> header   }}
  <body>
     {{> navbar   }}
    <div class="container">
      <div class="text">Registration</div>
      {{#if msg}}
      <p class="{{msg_type}}">{{msg}}</p>
      {{/if}}
      <form action="/auth/register" method="post">
        <div class="data">
          <label for="name">Full Name</label>
          <input type="text" name="name" id="name" />
        </div>
        <div class="data">
          <label for="email">Email</label>
          <input type="email" name="email" id="email" />
        </div>
        <div class="data">
          <label for="password">Password</label>
          <input type="password" name="password" id="password" />
        </div>
        <div class="data">
          <label for="confirm_password">Confirm Password</label>
          <input type="password" name="confirm_password" id="password" />
        </div>

        <div class="btn">
          <button type="submit">Register</button>
        </div>
        <div class="signup-link">
          Already a member ? <a href="/">Login now</a>
        </div>
      </form>
    </div>
  </body>
</html>
home.hbs
<!DOCTYPE html>
<html lang="en">
   {{> header   }}
  <body>
   
 {{> navbar   }}
    <div class="container-fluid">
      <h2>Home Page</h2>
    </div>
  </body>
</html>
profile.hbs
<!DOCTYPE html>
<html lang="en">
    {{> header }}
  <body>
  
    {{> navbar }}

    <div class="container-fluid">
      <h2>User Profile</h2>
      <img src="/images/profile.png" />
      <h3>Name : {{user.NAME}}</h3>
      <h3>Email : {{user.EMAIL}}</h3>
    </div>
  </body>
</html>

Conclusion

In this article, I demonstrated how to create a login form using Node.js and MySQL. Hope you can easily understand thank you "Happy Coding".