JWT Authentication

Bimlendu Kumar
6 min readMar 1, 2020

JWT is pretty easy to understand and after reading this article you will say the same.

Prerequisite

Before we get into action, there are few things you need to know and they are not fancy, you can google them. Even if you don't know them I will do my best to make it easy for you.

- Express, Express generator, MongoDB, Postman, VSCode

We will be writing code in vscode and will use postman to do all the requests. It will be better if you code with me. We will first set up our environment.

Setting Up The Environment

First, we will install express-generator globally.

npm install -g express-generator

Use this command to install express-generator globally. Now with the help of express-generator, we will set up our initials. To check if express-generator is installed or not. Type

express --help

and you will receive a bunch of options. Now we will set up our environment.

express --view ejs jwtauth

Copy and paste the above command in the command line. What this code will do is create a folder named jwtauth with view engine as ejs. We are going to use postman for all our queries so we do not need a view engine. Now

cd/jwtauth
npm install

This above code will install all the dependencies. Now open jwtauth folder in vscode. Our vscode will look like

We will install a few more dependencies

npm i --save mongoose jsonwebtoken bcrypt dotenv

mongoose package will help us to connect with the database, jsonwebtoken package will help us to keep track of the login user, bycrypt will help us to encrypt our password before we save it in the database, dotenv will help us to keep our secret to ourself. Don't worry even if you don't understand something right now, it will be clear as we proceed.

Now we will create our schema on how we are going to store the user information. Create a folder named models in the root directory. Inside models folder create user.js file.

var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var userSchema = new Schema({
name: String,
email: String,
password: String
});
module.exports = mongoose.model("User", userSchema);

Our user schema is set. Now we will connect MongoDB database to our app. Open app.js and add the following code at the beginning of the file.

var mongoose = require("mongoose");
var bcrypt = require("bcrypt");
var jwt = require("jsonwebtoken");

For now, we only need mongoose but I added bcrypt and jwt because we may need them later. Just before instantiating our app we will connect our database. This code will create a database named jwtauth if it doesn't exist, and connect with it.

mongoose.connect(
“mongodb://localhost/jwtauth”,
{
useNewUrlParser: true,
useUnifiedTopology: true
},
() => {
console.log(“connected to db”);
}
);

This is how our app.js file should look like.

now we will move on to verify user credentials. Create a folder named authentication in the root directory and inside it create a file name auth.js.

var jwt = require("jsonwebtoken");module.exports = {generateJWT: async user => {try {var payload = { userId: user.id, email: user.email };var token = await jwt.sign(payload, process.env.SECRET);return token;} catch (error) {next(error);}},verifyToken: async (req, res, next) => {var token = req.headers["authorization"] || "";if (token) {try {var payload = await jwt.verify(token, process.env.SECRET);req.user = payload;req.user.token = token;next();} catch (error) {res.json({ message: "invalid token", error });next();}} else {res.json({ msg: "Token required" });next();}}};

Copy and paste the above code in the auth.js file. In this code, there is two functions. generateJWT creates a token to be sent to the browser whenever a user logged in and after that whenever the user sends a request it checks if the user is authentic or not using the second function verifyToken. Here I have used process.env.SECRET which I will explain later.

As our authentication is ready we will define our routes. Inside the routes folder, there is a file named users.js. Copy and paste the below code.

var express = require("express");var router = express.Router();var User = require("../models/user");var auth = require("../authentication/auth");var jwt = require("jsonwebtoken");/* GET users listing. */router.get("/", function(req, res, next) {res.send("respond with a resource");});router.post("/register", async (req, res, next) => {try {var newUser = await User.create(req.body);res.status(200).json(newUser);} catch (error) {res.status(400).json("user not created");}});router.get("/login", async (req, res, next) => {var { email, password } = req.body;try {var user = await User.findOne({ email });if (!user) return res.json({ error: "email invalid" });var match = await user.verifyPassword(password);if (!match) return res.json({ error: "password does not match" });var token = await auth.generateJWT(user);res.json({ success: "true", token });} catch (error) {res.status(400).json(error);}});router.get("/profile", auth.verifyToken, async (req, res) => {try {var user = await User.findById(req.user.UserId);res.status(200).json({ success: true, user });} catch (error) {res.status(400).json({ msg: "User not found" });}});module.exports = router;

We will be using user schema to store data in the database. We will use

localhost:3000/users/register 
// post request to register user
localhost:3000/users/login
// get request to login
localhost:3000/users/profile
// to get user details

We haven't yet discussed how to hash our password. let's go back to user.js in models folder and this is how our file should look like

var mongoose = require("mongoose");var bcrypt = require("bcrypt");var Schema = mongoose.Schema;
var userSchema = new Schema({name: String,email: String,password: String});userSchema.pre("save", async function(next) {try {if (this.password && this.isModified("password")) {this.password = await bcrypt.hashSync(this.password, 10);next();}} catch (error) {next(error);}});userSchema.methods.verifyPassword = function(password) {return bcrypt.compareSync(password, this.password);};module.exports = mongoose.model("User", userSchema);

Here we are using prehook to hash our password and also have a method to verify the password.

Lets now talk about process.env.SECRET. What does this mean? we are encrypting user information and jwt need a secret string which is then used to encrypt this user login credentials. Thats why we store this string in .env file. So create this .env file in the root directory and inside it type

SECRET=HELLOTHISISJWTAUTH

Here SECRET is the key and HELLOTHISISJWTAUTH is our secret string. How our app will know where to look for this secret key. For that purpose, we use just after instantiating our app.

require(“dotenv”).config();

now we are all set for action. let's start our npm. Use command

npm start

Let's open our postman and register our new user

POST  localhost:3000/users/registersend body on json format somthing like
{
"name": "bimlendu",
"email":"bim240@gmail.com",
"password" : "123456"
}

we will get something like this and as you can see our password is hashed and even we can't figure out.

now we will log in using email and password

get  localhost:3000/users/loginsend body on json format somthing like
{
"email":"bim240@gmail.com",
"password" : "123456"
}

we will get something like,

{“success”: “true”,“token”: “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1ZTU2MWEzOGQ2NjMwZTIxYjI1ZjhmOGUiLCJlbWFpbCI6ImJpbTI0MEBnYW1pbC5jb20iLCJpYXQiOjE1ODMwODAyMTB9.1oqIN8hKUxE5hG_swP1AtA7jCmrhKXsSMDEKJuDEMAE”}

now we will see the details of the user. Bofore making a request first we will have to attach our token to the header so there is field called authorization in the header and in its value pass the token string. Our request will look like

get  localhost:3000/users/profile

and our result will look like

{"success": true,"user": {"_id": "5e561a38d6630e21b25f8f8e","name": "bimlendu","email": "bim240@gmail.com","password": "$2b$10$0O9RN2D1UPH5KKvx35OrOuMnGgWKk4Lriv4zqDaeNW9ok6sUgx3rS","__v": 0}}

This is the end. See you all in the next article . . . . . .

--

--