67-Nodejs Course 2023: Auth: Access Token When Login
Tags: node, typescript, mongodb, fastify
Published: 2022-11-18 08:29:39

---
title: 67-Nodejs Course 2023: Auth: Access Token When Login
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44miznshyp2azndc045b.png
# Use a ratio of 100:42 for best results.
---

So we have seen how we created `Current User` utility, which is a powerful one, but that one was only with the `Guest` user. Now we will see how we can create a `Current User` utility with the `Logged In` user.

## How this works

So let's see how this works first, we'll first check if the user is passing his/her credentials, if yes, then we'll check if the credentials are correct or not, if yes, then we'll create a `JWT` token and we'll pass the user payload to `JWT` when generating the token, this will be used to identify the user when he/she will make a request to the server again with the `JWT` token.

## Login Controller

Our login controller now looks like:

```ts
// src/app/users/controllers/login.ts
import User from "app/users/models/user";
import { Request } from "core/http/request";
import { Response } from "core/http/response";

export default async function login(request: Request, response: Response) {
  // get the email and password from the request body
  const { email, password } = request.only(["email", "password"]);

  const user = await User.attempt({ email, password });

  if (!user) {
    return response.badRequest({
      error: "Invalid credentials",
    });
  }

  console.log("Logged in successfully");

  // generate access token

  return response.success({
    user: user.data,
  });
}
```

As you can see, there is a comment in the controller `generate access token`, but sadly there is no generated token 🥺, so let's generate the token.

We already have our own `jwt` which can generate a new token, that's what we'll do right now.

## Generate Access Token

So let's create a new method in the `User` model, which will generate a new token for the user.

```ts
// src/app/users/controllers/login.ts
import User from "app/users/models/user";
import jwt from "core/auth/jwt";
import { Request } from "core/http/request";
import { Response } from "core/http/response";

export default async function login(request: Request, response: Response) {
  // get the email and password from the request body
  const { email, password } = request.only(["email", "password"]);

  const user = await User.attempt({ email, password });

  if (!user) {
    return response.badRequest({
      error: "Invalid credentials",
    });
  }

  // generate access token
  const token = await jwt.generate({
    ...user.only(["id", "_id"]),
    userType: "user",
  });

  return response.success({
    user: user.data,
    // send the access token to the client
    accessToken: token,
    // send the user type to the client
    userType: "user",
  });
}
```

Here we generated a new token using `jwt.generate` method, and we passed the user payload to the `jwt.generate` method, so that we can identify the user when he/she will make a request to the server again with the `JWT` token.

Now let's give it a try, and see if it works or not.

> Don't forget that the `/login` requires a Bearer Token, which will be in this case the `Guest` access token.

Now open Postman and make a `POST` request to the `/login` route, and pass the `email` and `password` in the request body.

> Don't forget to pass the `Authorization` header with the `Bearer` token.

You should see something like this:

![User resposne](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b94kr1wyjouzk6v4zp73.png)

From now on, we can use this access token to make requests to the server, now let's see if it works.

## Logged In User With list users

Now let's update the list users request to make it only accessible to the logged in user only.

We already have `authMiddleware` added  in the `/users` request, but we need to tell it allow only the `user` user type, so let's modify that middleware to receive a `userType` parameter, and we'll use that parameter to check if the user is of the same type or not.

If no arguments passed, it will be accessible to all the user types.

```ts
// src/core/auth/auth-middleware.ts
import config from "@mongez/config";
import { Request } from "core/http/request";
import { Response } from "core/http/response";
import { setCurrentUser } from "./current-user";
import jwt from "./jwt";

export async function authMiddleware(request: Request, response: Response) {
  try {
    // use our own jwt verify to verify the token
    await jwt.verify();
    // get current user
    const user: any = request.baseRequest.user;

    // now, we need to get an instance of user using its corresponding model
    const userType = user.userType;
    // get user model class
    const UserModel = config.get(`auth.userType.${userType}`);

    // get user model instance
    const currentUser = await UserModel.findBy("_id", user._id);

    // set current user
    setCurrentUser(currentUser);
  } catch (err) {
    // unset current user
    setCurrentUser(undefined);
    return response.badRequest({
      error: "Unauthorized: Invalid Access Token",
    });
  }
}
```

This is the current state of the middleware file, what're going to do now is what we call `Higher Order Function`

## Higher Order Function

A higher-order function is a function that does at least one of the following:

- Take one or more functions as an input
- Output/Return a function

It can be one of these cases or `both`.

In our case, we're going to create a function that takes a `userType` parameter, and returns a function that will be used as a middleware.

```ts
// src/core/auth/auth-middleware.ts
import config from "@mongez/config";
import { Request } from "core/http/request";
import { Response } from "core/http/response";
import { setCurrentUser } from "./current-user";
import jwt from "./jwt";

export function authMiddleware(allowedUserType?: string) {
  return async function auth(request: Request, response: Response) {
    try {
      // use our own jwt verify to verify the token
      await jwt.verify();
      // get current user
      const user: any = request.baseRequest.user;

      // now, we need to get an instance of user using its corresponding model
      const userType = user.userType;

      // check if the user type is allowed
      if (allowedUserType && userType !== allowedUserType) {
        return response.unauthorized({
          error: "You are not allowed to access this resource",
        });
      }

      // get user model class
      const UserModel = config.get(`auth.userType.${userType}`);

      // get user model instance
      const currentUser = await UserModel.findBy("_id", user._id);

      // set current user
      setCurrentUser(currentUser);
    } catch (err) {
      // unset current user
      setCurrentUser(undefined);
      return response.unauthorized({
        error: "Unauthorized: Invalid Access Token",
      });
    }
  };
}
```

Here we moved the auth middleware function into the function and called it `auth`, this is a kind of nested functions, a function inside a function and we also returned it. the `authMiddleware` function now can receive a `userType` parameter, and it will return a function that will be used as a middleware.

Then we checked if the `allowedUserType` is passed, and if it's passed, we checked if the user type is the same as the `allowedUserType`, if not, we'll return an `unauthorized` response.

Now let's update the `/users` route to use the `authMiddleware` with the `user` user type.

```ts
// src/app/users/routes.ts
import { authMiddleware } from "core/auth/auth-middleware";
import router from "core/router";
import login from "./controllers/auth/login";
import createUser from "./controllers/create-user";
import getUser from "./controllers/get-user";
import usersList from "./controllers/users-list";

router.get("/users", usersList, {
  middleware: [authMiddleware("user")],
});

router.get("/users/:id", getUser);
router.post("/users", createUser);
router.post("/login", login);
```

Now let's try to make a request to the `/users` route, and see if it works or not.

Try first with no `Authorization` header, you should see a unauthorized response.

Then try it with `guest` access token, you should see an unauthorized response.

Now try it with `user` access token that we got from `/login` request, you should see a list of users.

## Current User as Logged In User

Now we can use the `user` function to get the current user, and we can use it in the `usersList` controller.

```ts
// src/app/users/controllers/users-list.ts
import { user } from "core/auth/current-user";
import database from "core/database";
import { Request } from "core/http/request";

export default async function usersList(request: Request) {
  const usersCollection = database.collection("users");

  // log the current user

  const users = await usersCollection.find({}).toArray();

  console.log(user());

  return {
    users,
  };
}
```

You should see the logged in user in the console, you should see the logged in user in the console.

![Logged In User](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cpi8657gn7b2wvokmwtc.png)

## 🎨 Conclusion

In this article, we learned how to generate a JWT for logged in user, and also how to make a middleware to protect routes based on user type.

## ☕♨️ Buy me a Coffee ♨️☕

If you enjoy my articles and see it useful to you, you may [buy me a coffee](https://www.paypal.com/paypalme/hassanzohdy), it will help me to keep going and keep creating more content.

## 🚀 Project Repository

You can find the latest updates of this project on [Github](https://github.com/hassanzohdy/nodejs-2023)

## 😍 Join our community

Join our community on [Discord](https://discord.gg/pb2vmdfhGf) to get help and support (Node Js 2023 Channel).

## 🎞️ Video Course (Arabic Voice)

If you want to learn this course in video format, you can find it on [Youtube](https://www.youtube.com/playlist?list=PLGO8ntvxgiZMJc7RN2lIq9WmMOlWZGzmz), the course is in Arabic language.

## 📚 Bonus Content 📚

You may have a look at these articles, it will definitely boost your knowledge and productivity.

General Topics

- [Event Driven Architecture: A Practical Guide in Javascript](https://dev.to/hassanzohdy/event-driven-architecture-the-best-paradigm-that-i-love-to-work-with-in-javascript-and-node-js-1gnk)
- [Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript](https://dev.to/hassanzohdy/best-practices-for-case-styles-camel-pascal-snake-and-kebab-case-in-node-and-javascript-55oi)
- [After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
](https://dev.to/hassanzohdy/after-6-years-of-practicing-mongodb-here-are-my-thoughts-on-mongodb-vs-mysql-574b)

Packages & Libraries

- [Collections: Your ultimate Javascript Arrays Manager](https://dev.to/hassanzohdy/collections-your-ultimate-javascript-array-handler-3o15)
- [Supportive Is: an elegant utility to check types of values in JavaScript](https://dev.to/hassanzohdy/supportive-is-an-elegant-utility-to-check-types-of-values-in-javascript-1b3e)
- [Localization: An agnostic i18n package to manage localization in your project](https://dev.to/hassanzohdy/mongez-localization-the-simplest-way-to-translate-your-website-regardless-your-favorite-framework-4gi3)

 React Js Packages

- [useFetcher: easiest way to fetch data in React Js](https://dev.to/hassanzohdy/usefetcher-the-easiest-way-to-fetch-data-in-react-45o9)

Courses (Articles)

- [OOP In JS And TS From The Very Beginning](https://dev.to/hassanzohdy/jsts-oop-course-1-introduction-2ld)
- [ES6++: The Ultimate Guide to ES6 and Beyond](https://dev.to/hassanzohdy/es6-1-introduction-h3e)
- [React Js: Let"s Create File Manager With React Js and Node Js](https://dev.to/hassanzohdy/lets-create-a-file-manager-from-scratch-with-react-and-typescript-chapter-i-a-good-way-to-expand-your-experience-5g4k)