How to use JWT Authentication in NodeJs/NextJs
Tags: node, nextjs, tutorial, javascript
Published: 2023-04-15 02:02:11

## What is JWT
JSON web token (JWT), pronounced "jot", is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. (Definition from auth0.com)

In a layman's term, it basically provides a way to convert JSON object into a string using the key we provide to it.

The output of JWT, the obtained string, is used to transfer the information between client and server securely.

We can use for authentication, which is mostly done through **middleware**

## What is Middleware
Sometimes we need to modify the request sent by the client. Let's say client is sending us the the user_id of himself, but we do not know the other the information, like email, related to client.

One of of doing it is to fetch the data within the **request handler function** (as app.post is request handler function in nodejs/express). This is all fine, but the problem with this type of handling is that this makes code somewhat **unclean** and effects the **readability** of code.

Other way of doing it is to make a middleware, which will be a separate function, other than request handler function and preferably in separate file. Middleware accepts 3 arguments, request, response and next. 

```
export const authenticate = (req, res, next)=>{
     ...
}
```

Request and response are same as request handler functions, i.e, request will contain the data sent by the client, and response will be used to send the response back to client.

Next argument is a function which, when called, move the request to the next handler, i.e, either next middleware function or the final request handler function. It depends upon how you chain the middlewares at request handler function.

For example:

```
app.get(authenticate, async(req, res)=>{
     ...
}
```

In the above case, we are calling the authenticate middleware and then our final request handler function.

Above authenticate middleware function looks like this:

```
export const authenticate = (req, res, next)=>{
if(<authentication successful>){
next()
}
else{
return res.status(401).json({success: false, message: "You are not logged in"})
}
```


## How to use JWT along with middlewares
So first, when user **signup** or **login**, we need to generate the JWT with user details, mostly with user id.

This is what my signup looks like:
```
import Users from "../../backend/models/Users"
import dbConnect from "../../backend/utils/dbConnect"
import { signToken } from "../../backend/utils/jwt"


export default async function handler(req, res) {

  if(req.method != "POST")
    return res.status(404).json({success: false, message: "Method Not Found"})


  if(!req.body.email || !req.body.password || !req.body.name)
    return res.status(400).json({success: false, message: "Please Provide Email, Password and Name"})

  await dbConnect()

  const {email, password, name} = req.body

  try{

  let userFound = await Users.findOne({email})
  if(userFound)
    return res.status(401).json({success: false, message: "Email Already Registered"})

  let user = new Users({email, password, name})
  await user.save()

  let jwtToken = signToken({id: user.id}, process.env.NEXT_PUBLIC_JWT_SECRET)
  return res.status(200).json({success: true, data: {token: jwtToken}})

  }
  catch(err){
    console.log(err)
    return res.status(500).json({succes: false, message: "Some Error Occured In Server, Error: " + err})
  }
  
}
```

The line: 
`let jwtToken = signToken({id: user.id}, process.env.NEXT_PUBLIC_JWT_SECRET)`
returns a string (jwt toke) based on the object provided as first argument and the key provided as second argument (process.env.NEXT_PUBLIC_JWT_SECRET is key present in .env file, an environment variable)

We need to send jwt token, (string returned by signToken), to the client and the client will save it as cookie. And with every request, client will send this jwt as authorization in header as 'Bearer jwt_token'.

Our authenticate middleware function looks like this:

```
import jwt from 'jsonwebtoken'

export const authenticate = (req, res, next)=>{
    if(!req.headers.authorization)
        return res.status(401).json({success: false, message: "User Not Authorized"})

    let token = req.headers.authorization
    
    // Bearer token
    token = token.split(" ")[1]
    try{
        let user = jwt.verify(token, process.env.NEXT_PUBLIC_JWT_SECRET)
        req.user = user
        next()
    }
    catch(err){
        return res.status(401).json({success: false, message: "User Not Autorized"})
    }
}
```

You can see that, authentication middleware function is extracting the **req.headers.authorization** which contains our JSON web token, sent by client in this format: "Bearer jwt_token"
So, we are getting the token by splitting the string with "white space" as delimiter and extracting the string at 2nd index, which is our JWT.

Now we verify it using jwt.verify function, which takes jwt token as first argument and secret key as second argument.

This will return the object that we provided while creating the jwt token.

We will use this object and store in request so that it can be used by next request handler function by simply:
`req.user = user` and then we will call `next()`

In case, jwt does not verify the token provided by client, we will simply response back, within the authentication middleware function, as
`return res.status(401).json({success: false, message: "User Not Autorized"})`



**That's it, Hope it helped you out**