Authentication and Authorization using AccessTokens - RefreshTokens | Part 2
Tags: javascript, jwt, authentication, authorization
Published: 2021-05-31 07:03:17

#Authorization
##Session based authorization
Earlier developers were using `session` based authorization.
After the user logs in, a session Id is sent to client in form of a cookie and when there is a user request, the server checks for that cookie and gives access and response.

![JWT](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mj6qwejoaawhsilwwepc.png)

###Drawbacks
* The problem is sessions are stored in the server, and when the app scalability increases, user requests also increase which eventually put loads on the server.
* It doesn't support multiple servers. For example, suppose user logs in to the 'Amazon' website then the session id is passed to the client, but if the same user wants to open 'Amazon Prime', the user has to log in once again to create a session id.


##JWT based authorization
In this process, when the user logs in, the user information is signed with a secret (which is stored in the server) and a JSON web token is generated and it is sent to the client. Generally, it is stored in browser localStorage, whenever a user sends a request to the server in which the authorization token is present in the `headers` of the request , the server just verifies that JWT token with the secret it has by unsigning that JWT token and gives users access.

![cookie sessions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klkwtehuc9xfnmt7dcqh.png)

###Why JWT?
* All the user state is stored on the client-side, so there is no load on the server.
* It supports multiple servers by just passing the secret to multiple servers for verification.

###Implementation using AccessToken and RefreshToken
* `RefreshToken` is used to generate new `AccessToken` when it expires. `AccessToken` contains the user state or information and `RefreshToken`.
* When user logs in, server creates `AccessToken` and `RefreshToken` stores the userId or something which when unsigns by someone, the person would not understand the context, and it returns response to the client. Usually `AccessToken` expires after a short time and `RefreshToken` after a long time.
```javascript
router.post('/signin', async (req, res) => {
  try {
    const user = await req.body;
    const { email, password } = user;
    const userEmail = email;

    await User.findOne({ email: userEmail })
      .exec((err, user) => {
        if (err || user === null) {
          return res.status(400).json({
            message: "user does not exists!",
          });
        } else if (!user.authenticate(password)) {
          return res.status(401).json({
            message: "please enter the correct password!",
          });
        }
        const accessToken = jwt.sign(
          { user },
          process.env.ACCESS_TOKEN_SECRET,
          {
            expiresIn: "15m",
          }
        );
        const refreshToken = jwt.sign(
          { userId: user._id },
          process.env.REFRESH_TOKEN_SECRET,
          {
            expiresIn: "7d",
          }
        );
        res.json({ user, accessToken, refreshToken });
      });
  } catch (error) {
    res.status(400).json({
      message: error.message,
    });
  }
})
```
* Then we can make a middleware for the verification of the token and put it in any route for authorization.
```javascript
exports.authorizeToken = async (req, res, next) => {
  if (
    !req.headers["authorization"] &&
    typeof req.headers["authorization"] !== "string"
  ) {
    return res.status(401).json({
      message: "No tokens found",
    });
  }

  try {
    const accessToken = req.headers["authorization"].split(" ")[1];
    const { user } = jwt.verify(accessToken, process.env.ACCESS_TOKEN_SECRET);
    req.user = user;
    return next();
  } catch (error) {
    res.status(401).json({
      message: "token cannot be verified! please check it again.",
    });
  }
};
```

* Before `accessToken` gets expire, we generate another `accessToken` in server from the `refreshToken` we got from the client's request. Then we send both the tokens to the client.
```javascript
router.post('/token/access', (req, res) => {
  if (
    !req.headers["refresh-token"] &&
    typeof req.headers["refresh-token"] !== "string"
  ) {
    return res.status(401).json({
      message: "No refresh tokens found",
    });
  }

  try {
    const oldRefreshToken = req.headers["refresh-token"].split(" ")[1];
    const { userId } = jwt.verify(
      oldRefreshToken,
      process.env.REFRESH_TOKEN_SECRET
    );
    const refreshToken = jwt.sign(
      { userId: userId },
      process.env.REFRESH_TOKEN_SECRET,
      {
        expiresIn: "7d",
      }
    );
    const accessToken = jwt.sign(
      { user },
      process.env.ACCESS_TOKEN_SECRET,
      {
        expiresIn: "15m",
      }
    );
    res.json({ accessToken, refreshToken });
  } catch (error) {
    res.status(401).json({
      message: "refresh token cannot be verified! please check it again.",
    });
  }
})
```
* The `refreshToken` is generally stored in the `localStorage` of the browser and the `accessToken` is stored in the headers of the API requests.

Voila! your app is now secured with the `authentication` and `authorization`.
Hope you find this useful.

*references*
*cover image : https://jwt.io/*
*youtube: https://www.youtube.com/watch?v=7Q17ubqLfaM&t=332s*