Authentication and Authorization Using JWT in Node JS with Express
Tags: javascript, webdev, career, beginners
Published: 2020-12-12 22:01:32

# Table Of Contents
* [What is authentication & authorization ?!](#chapter-1)
* [What is (JWT)JSON Web Token? ](#chapter-2)
* [Why using Authentication & Authorization ? ](#chapter-3) 
* [How apply Authentication ? ](#chapter-4) 
* [How apply Authorization ? ](#chapter-5) 
* [Conclusion](#chapter-6)

# Introduction

User authentication & authorization is one of the important part of any web application. 
There are several kinds of way to handle authentication, we can rely on third party service like Passport. 
But in this article we will use very simple & self developed approach, which will help us to understand core part of authentication.

## Technology Used
Token: JWT
Password Hash: bcryptjs
Database: MongoDB

# What is authentication & authorization ?! <a name="chapter-1"></a>

In simple words, **Authentication** is the process of verifying who a user is (who you are), and 
**Authorization** is the process of verifying what they have access to (what you are allowed to do).

![haa](https://media.giphy.com/media/KXY5lB8yOarLy/giphy.gif)

# What is (JWT)JSON Web Token ?! <a name="chapter-2"></a>
**JWTs** are a good way of **securely transmitting information between parties** because they can be signed (Information Exchange). Even though we can use JWT with any type of communication method, today JWT is very popular for handling authentication and authorization via HTTP.
### Here is the diagram of how JWT works:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9vlykphw826cpsnfue7b.png)

# Structure of a JWT :- 
1. The **first section** of the JWT is the **header**, which is a Base64-encoded string. 
which contains the hashing algorithm, which was used to generate the sign and the type of the token.
If you decoded the header it would look something similar to this:
`{   "alg": "HS256",    "typ": "JWT"}`

2. The **second sectio**n is **the payload that contains the JSON object of user data** like (id or id_type) that was sent back to the user.
 Since this is only Base64-encoded, it can easily be decoded by anyone.

 `{"sub": "1234567890", "name": "John Doe",    "userId": "1516239022", "user_type_id":1 }`

3. The **final section** is the **signature of the token** using the algorithm that is mentioned in the header section

![Structure of a JWT](https://dev-to-uploads.s3.amazonaws.com/i/z1ju9v1pwi7b3gskr2ot.PNG)


# Why using Authentication & Authorization ?! <a name="chapter-3"></a>

To **protect the data** in a security system, administrators should be able to, among other things, implement detailed user **access privileges**, select the information that can be shared internally with partners and authorities, and **control** how long data is kept.

**A common example** is entering a username and password when you log in to a website.
 Entering the correct login information lets the website know 

 1) Who you are and
 2) That it is actually you accessing the website.

![Let's Start](https://media.giphy.com/media/vtYHCDsmiYtEr977Zf/giphy.gif)

## There will be two **types of users** (admin & user)
**Authentication** that all user need to login and register first , 
**Authorization** that administrators and the regular user. Administrators will be able to view special events 
whereas the regular user will be able to view ordinary events 

To get **started** in this trip, I have REST APIs already created (including **4 Routes**) [GitHub repo](https://github.com/mohamedlotfe/Auth-Using-JWT-with-Express/tree/main)

1- POST login route ( everyone has access)
2- POST register route ( everyone has access)
3- GET events array (only regular user has access)
4- GET special events array (only admin user has access)

# How apply Authentication ?! <a name="chapter-4"></a>

### Step (1)
 1. To get started, in your terminal initialize an empty Node.js project with default settings:
`$ npm init -y`

 2. Then, let's install the Express framework, JWT, bcryptjs and mongoose:
`$ npm install --save express jsonwebtoken bcryptjs` 

 3. Then To create basic structure for different kind of endpoints like registration or login we will use express as router. And we will create a folder for routers (routers/index.js)

 4. Then, let's create a file called `(middleware/auth.js)`, which will be our authentication service and create a file called `(controllers/user)`, which will be our controller for user functions
 5. Now, let's create our Server and use these modules and configure them in the Express app (server.js):
```javascript
const express = require('express');
const app = express();

app.use(express.json()); 

// Import Routes
const authRoute = require('./routes/index');
 
// Route Middlewares
app.use('/api', authRoute);

const port = 3000;
app.listen(port, function(){console.log("Server running on localhost:" + port);});
```
### Step (2)
 1. Now go for folder for routers `(routers/index.js)` to configure express Router import userController
```javascript
const router = require('express').Router();
const userController = require('../controllers/user');

// Register a new User
router.post('/register', userController.register);

// Login
router.post('/login', userController.login);

module.exports = router;
```
### Step (3)
Now go for folder for routers `(controllers/user)` to add userController functions
 1.Connect to DB 
```javascript
mongoose.connect(db, function(err){
    if(err){
        console.error('Error! ' + err)
    } else {
      console.log('Connected to mongodb')      
    }
});
```
 2. Create register function
  * Hash password using bcrypt module
  * Create an user object
  * Save User in the database
  * Create payload then Generate an access token (if you ask about what is payload go for Structure of a JWT section)
```javascript
exports.register = async (req, res) => {
    //Hash password
    const salt = await bcrypt.genSalt(10);
    const hasPassword = await bcrypt.hash(req.body.password, salt);

    // Create an user object
    let user = new User({
        email: req.body.email,
        name: req.body.name,
        password: hasPassword,
        user_type_id: req.body.user_type_id
    })

    // Save User in the database
    user.save((err, registeredUser) => {
        if (err) {
            console.log(err)
        } else {
            // create payload then Generate an access token
            let payload = { id: registeredUser._id, user_type_id: req.body.user_type_id || 0 };
            const token = jwt.sign(payload, config.TOKEN_SECRET);
            res.status(200).send({ token })
        }
    })
}
```
##After the authentication service is up and **running**, let's send a POST request and see if registration works or not.

* I will be using the rest-client **Postman** to do this. Feel free to use any rest-client you prefer or something like Insomnia to do this.
 * Let's send a post request to the `http://localhost:3000/api/register` endpoint with the following JSON:
`{
    "email":"d@a.hh",
    "name" : "lotfy",
    "password": "123456",
    "user_type_id":1
}`
 * You should get the access token as the response:
`{
  "Token": "eyJhbGciOiJIUz..."
}`


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v6yq8kntfebsesnztos7.PNG)

### Step (4)
Now we register for new user and token receive token as response
we need to login with user credentials 
 1. create login function
  * compare Hashed password with credentials
  * create payload then Generate an access token and return token in headers
  ```javascript
exports.login = async (req, res) => {

    User.findOne({ email: req.body.email }, async (err, user) => {
        if (err) {
            console.log(err)
        } else {
            if (user) {
                const validPass = await bcrypt.compare(req.body.password, user.password);
                if (!validPass) return res.status(401).send("Mobile/Email or Password is wrong");

                // Create and assign token
                let payload = { id: user._id, user_type_id: user.user_type_id };
                const token = jwt.sign(payload, config.TOKEN_SECRET);

                res.status(200).header("auth-token", token).send({ "token": token });
            }
            else {
                res.status(401).send('Invalid mobile')
            }

        }
    })
}
  ```
## let's send a POST request and see if Login works or not.

 * Let's send a post request to the `http://localhost:3000/api/login` endpoint with the following JSON:
`{
    "email":"d@a.hh",
    "password": "123456"
}`
 * You should get the sucess with 200 code and access token in the header of response:
`
  "auth-token": "eyJhbGciOiJIUz..."
`
![Login](https://dev-to-uploads.s3.amazonaws.com/i/ymbqaz4ee3vybuiexepu.PNG)

# How apply Authorization ?! <a name="chapter-5"></a>
As we mentioned in Authentication steps (register/login) 
We added property called "user_type_id" which is identifier for type of user is request this data


### Step (1)
Now we need if the request for logged in user or some hack my APIs
let's move to our auth file in `(middleware/auth.js)`
  * Check if request have an access token
  * Remove Bearer from string which added in header of request
  * Verify User Token with my token `secretKey`
```javascript
exports.verifyUserToken = (req, res, next) => {
    let token = req.headers.authorization;
    if (!token) return res.status(401).send("Access Denied / Unauthorized request");

    try {
        token = token.split(' ')[1] // Remove Bearer from string

        if (token === 'null' || !token) return res.status(401).send('Unauthorized request');

        let verifiedUser = jwt.verify(token, config.TOKEN_SECRET);   // config.TOKEN_SECRET => 'secretKey'
        if (!verifiedUser) return res.status(401).send('Unauthorized request')

        req.user = verifiedUser; // user_id & user_type_id
        next();

    } catch (error) {
        res.status(400).send("Invalid Token");
    }

}
```
  * Now we need know type for logged-in user 
```javascript
exports.IsUser = async (req, res, next) => {
    if (req.user.user_type_id === 0) {
        next();
    }
    return res.status(401).send("Unauthorized!");   
}
exports.IsAdmin = async (req, res, next) => {
    if (req.user.user_type_id === 1) {
        next();
    }
    return res.status(401).send("Unauthorized!");

}
```
### Step (2)
Now we verified user but need to **know is this route for administrators  or regular user**
with my **authentication middleware** to check  routes with user type to file `(routers/index.js)`

 * If these valid conditions call get user events function
```javascript
// Auth user only
router.get('/events', verifyUserToken, IsUser, userController.userEvent);

// Auth Admin only
router.get('/special', verifyUserToken, IsAdmin, userController.adminEvent);
```
### let's send a request and see if **special route** works for **admin user with user_type_id == 1**.

 * Let's send a post request to the `http://localhost:3000/api/special` endpoint with the following authorization header with TYPE `Bearer Token` and value of token:`eyJhbGciOiJIUz...`

 * You should get the success with 200 code and the special events array as a response:
`  { "_id": "1", "name": "Auto Expo Special", 
  "description": "lorem ipsum",  "date": "2012-04-23T18:25:43.511Z" } .....
`
![special Array](https://dev-to-uploads.s3.amazonaws.com/i/r8gm0ijy8f4cra66vrlx.PNG)

# Conclusion ?! <a name="chapter-6"></a>
In this article, we have introduced you to JWT and how to implement JWT with Express. I hope that now you have a piece of good knowledge about how JWT works 

The end Thank you for going through this tutorial. If you notice any errors please report them to me. If you got stuck on any step, please refer to this [GitHub repo](https://github.com/mohamedlotfe/Auth-Using-JWT-with-Express/tree/main).

You can contact me through:

Gmail: mhmdlotfy9@gmail.com
or [Linkedin](https://www.linkedin.com/in/mohamedlotfybasher/)