How to protect a URL inside a NestJS App using RBAC Authorization
Tags: javascript, tutorial, nestjs, webdev
Published: 2023-07-26 06:45:22

---
title: How to protect a URL inside a NestJS App using RBAC Authorization
published: true
date: 2023-06-30 06:45:00 UTC
tags: javascript, tutorial, nestjs, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e66277xsq0fvs0m9yelz.jpeg
canonical_url: https://www.permit.io/blog/how-to-protect-a-url-inside-a-nestjs-app-using-rbac-authorization
---

TL;DR: Enhance the security of your Nest.js API endpoints with Permit.io — a powerful tool for implementing authorization and access control. Ensure only authorized users have access to sensitive data.

Building secure and reliable API endpoints is crucial when developing applications with Nest.js. In this blog post, we will explore how you can enhance the security of your Nest.js APIs using Permit.io — a tool specifically designed for access control. By integrating Permit.io into your Nest.js project, you can ensure that only authorized users can access your API endpoints, protecting sensitive data and preventing unauthorized actions. 

## What we will cover:

1. 
Setting up a Nest.js Project
2. 
Working with Nest.js Passport library
3. 
Writing a decorator guard
4. 
Setting up our first policy with Permit
5. 
Installing and Initializing Permit
6. 
Writing the enforcement code

You’ll need: The latest Node.js version installed, a simple understanding of Express, and familiarity with Typescript.

## Setting up a Nest.js Project

To start, we need to install the Nest.js CLI globally. Open your terminal or command prompt and run the following command:

```bash
npm install -g @nestjs/cli
```

This will install the Nest.js CLI, which provides useful commands for generating modules, controllers, and more. Now, let’s create a new Nest.js project for our `nestjs-authz-guard`. Navigate to the directory where you want to create your project and run the following command:

```bash
nest new nestjs-authz-guard
```

This command will create a new Nest.js project structure with all the necessary files and folders. Let’s enter this project by running:

```bash
cd nestjs-authz-guard
```

Next, we’ll start the development server and see our blog application in action. Run the following command:

```bash
npm run start:dev
```

Navigate to [`http://localhost:3000`](http://localhost:3000 "http://localhost:3000") and you should see the below screen. Congratulations, you have set up a Nest.js project!

 ![nest-1.png](https://media.graphassets.com/HUwQ3ZZmS5mPzMc3dSjT "nest-1.png")
## Working with Next.js Passport library

[Passport](https://github.com/jaredhanson/passport "https://github.com/jaredhanson/passport") is the most popular node.js authentication library, well-known by the community, and successfully used in many production applications. Integrating this library with a Nest application using the `@nestjs/passport` module is a rather straightforward process. At a high level, Passport executes a series of steps to:

- Authenticate a user by verifying their credentials (such as username/password, JSON Web Token [[JWT](https://jwt.io/ "https://jwt.io/")], or identity token from an Identity Provider)
- Manage the authenticated state (by issuing a portable token, such as a JWT, or creating an [Express session](https://github.com/expressjs/session "https://github.com/expressjs/session"))
- Attach information about the authenticated user to the `Request` object for further use in route handlers

We will install the passport to create a Decorator Guard for our Authorization logic.

```bash
npm install @nestjs/passport
```

## Writing our Nest.js Decorator Guard

To start, let’s create another folder in our `/src` folder inside the project. We can name this folder `auth`. Next, inside, let’s create a file called `permissions.guard.ts`.

 ![nest-2.png](https://media.graphassets.com/qziiuKWfSeAzBBywKGJs "nest-2.png")

In the guard, we’ll house the logic to determine whether a specific user is granted permission to perform certain actions. In this tutorial, we assume the authentication aspect is already implemented, implying that user identity has been verified and a JWT (JSON Web Token) containing a unique user ID is available.

You can find a guide for implementing secure authentication with Nest.js [here](https://docs.nestjs.com/security/authentication "https://docs.nestjs.com/security/authentication").

Next, inside our `permissions.guard.ts` file, let’s add some logic.

```ts
// auth/permissions.guard.ts

import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class PermissionsGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();

    // Add the authorization logic here with Permit.io.
    // If the user has the necessary permissions, it will return true.
    // If the user does not have the necessary permissions, 
    // throw an UnauthorizedException.

    const userHasPermission = false; // <- replace this line with your Permit.io logic

    if (!userHasPermission) {
      throw new UnauthorizedException('You do not have the necessary permissions.');
    }
    return true;
  }
}
```

Currently, we are hard coding the state of the permission. We are always setting it to `false`. Let’s navigate to our `app.controller.ts` file and add another API endpoint path which we will try to protect.

```ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { PermissionsGuard } from './auth/permissions.guard';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  @UseGuards(PermissionsGuard)
  @Get('protected')
  getProtectedEndpoint(): string {
    return 'This is a protected route, but you have access.';
  }
}
```

Here we imported our `PermissionsGuard` and added a `useGuard` decorator. 

Then we created another `@Get` request, where we passed in our endpoint name (`protected`). We wrapped it with a `useGuard()` decorator, which means that if we navigate to [`http://localhost:3000/protected`](http://localhost:3000/protected "http://localhost:3000/protected") we should see this:

 ![nest-3.png](https://media.graphassets.com/toU81WHLSKWLwARGzuaH "nest-3.png")

Now, let’s change the outcome of the Guard logic to return `true`.

```ts
const userHasPermission = true;
```

Now we should have access to the `protected` route.

 ![nest-4.png](https://media.graphassets.com/UN6QbKs0QW2w2oFPz2oc "nest-4.png")

Hurray! We did it. Now it’s time to add Permit’s authorization logic.

## Setting up our first policy with Permit 

First, go ahead and create an account at [https://app.permit.io](https://app.permit.io/ "https://app.permit.io/"). You will be presented with an onboarding, but once you enter your organization name, you can just **skip** the setup (As we will be going through the same steps here, with a more detailed explanation). 

Once in the dashboard, navigate to the policy screen to the role manager. You will be prompted yo manage your first new role:

 ![nest-5.png](https://media.graphassets.com/4qwrdNgTRhyk1TB2iI2Q "nest-5.png")

Let’s create our first role. Each role will have specific rules associated with it, of what a user can and cannot do. The role we will create is an `Admin` role. The `/protected` page will only be accessible to users with the `Admin` role. 

To learn more about building RBAC (Role-based Access Control) policies — check out our guide [here](https://docs.permit.io/features/policy-editor/rbac/overview "https://docs.permit.io/features/policy-editor/rbac/overview").

 ![nest-6.png](https://media.graphassets.com/X7fUunETwiOAp8dn7MDl "nest-6.png") ![nest-7.png](https://media.graphassets.com/vhuMKp2kQlSFSWXv3Do0 "nest-7.png")

Success!

Now let’s navigate to the Users panel — we’ll add a sample user and assign them with the `Admin` role. 

In general, this would be the user and their unique ID that you would get from the JWT (JSON Web Token) upon successful authentication, but for this demo, we will just fake that process and pretend it has already happened.

If you need suggestions on the best Authentication Providers to work with, [**message us on**  **Slack**](https://io.permit.io/permitslack "https://io.permit.io/permitslack"), and we will be more than happy to suggest some.

You can also check out a guide on adding a user to Permit after successful authentication with [Auth0](https://auth0.com/ "https://auth0.com/") [here](https://www.permit.io/blog/add-rbac-authorization-to-auth0 "https://www.permit.io/blog/add-rbac-authorization-to-auth0").

 ![nest-8.png](https://media.graphassets.com/3T9h0DfFSQWLRQNIjzXO "nest-8.png")

You can name the user however you’d like.

Next, we’ll navigate to the Policy panel and create our first policy. First, we need to manage and create our first `resource`. You will be prompted to do so on the screen. 

Let’s call our resource `protected-page` (because that’s what the user will be trying to gain access to). As for the actions that a user will be able to perform on this resource, we only specified `view`. If you have more actions a user could perform, you can add them as needed. 

 ![nest-9.png](https://media.graphassets.com/w2ApUBETtSk56prQJ85M "nest-9.png") ![nest-10.png](https://media.graphassets.com/PyeEu937RBqPepkD0aN5 "nest-10.png")

If we now look at the policy editor, we will see a grid-like view where the `Admin` role contains a `protected-page` resource, which contains the `view` action that we can check for. 

 ![nest-11.png](https://media.graphassets.com/qNudyFIMRMy9cgWSJKPt "nest-11.png")

Let’s quickly add another role — we’ll all it `Manager`.

 ![nest-12.png](https://media.graphassets.com/CxmPFluXQz0ztQlaiGDg "nest-12.png")

 ![nest-13.png](https://media.graphassets.com/d0mlfxR7TlmyVphgpYfl "nest-13.png")

As we create another role, it automatically contains the previously defined resources and actions. As you can see, managing permissions and adding on top of them is extremely simple and fast. 

 ![nest-14.png](https://media.graphassets.com/Cgmp0BKRNK5Oa0eu9N0X "nest-14.png")

Finally, and most importantly, let’s check the permission to view the page for the Admin role. 

 ![nest-15.png](https://media.graphassets.com/1O0KUEtRtmzWzhGTo4Sg "nest-15.png")

Our RBAC policy is now configured. Time to write some simple code to get this to work!

## Installing and Initializing Permit

First, let’s install the npm package.

```bash
npm install permitio
```

Now, let’s import the package and add the Permit instance inside our Guard. 

```ts
// auth/permissions.guard.ts

import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { Observable } from 'rxjs';
// Permit package import
import { Permit } from 'permitio';

// This line initializes the SDK and connects your app
//to the Permit.io Cloud PDP.
const permit = new Permit({
    pdp: "https://cloudpdp.api.permit.io",
    // your API Key
    token: "[YOUR_API_KEY]",
});
```

Make sure to replace the API key with your unique API Key obtained from the Permit dashboard. To do so, click on your name in the dashboard and directly copy the API key from there.

 ![nest-16.png](https://media.graphassets.com/BOZKxNbARUKYrNsRenmF "nest-16.png")
## Writing the enforcement code

It’s now time to add the `permit.check()` function to our guard! Here is what the code will look like:

```ts
// auth/permissions.guard.ts

import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Permit } from 'permitio';

// This line initializes the SDK and connects your app
// to the Permit.io Cloud PDP.

const permit = new Permit({
    pdp: "https://cloudpdp.api.permit.io",
    // your API Key
    token: "[YOUR_API_KEY]",
});

@Injectable()
export class PermissionsGuard implements CanActivate {
  async canActivate(
    context: ExecutionContext,
  ): Promise<boolean> {
    const request = context.switchToHttp().getRequest();

    // Add the authorization logic here with Permit.io.
    // If the user has the necessary permissions, return true.
    // If the user does not have the necessary permissions, throw an UnauthorizedException.

    const userHasPermission = await permit.check("demo_user@gmail.com", "view", "protected-page");

    console.log(userHasPermission);

    if (!userHasPermission) {
      throw new UnauthorizedException('You do not have the necessary permissions.');
    }
    return true;
  }
}
```

Notice that we changed the `canActivate` function to be `async`, so that we can `await` for the `permit.check()` to return the `Promise`.

Inside the `permit.check()` function, we pass three parameters. The unique `key/id` of the user, which in this case is the email, the `action` we are performing, and the `resource` we are performing that action on. Permit will check this against the policy we have defined and return a `boolean` based on the outcome of the permission check.

Because we assigned the `Admin` role to our user, we should have the permissions to access the page — let’s call the `/protected` route and see.

 ![nest-17.png](https://media.graphassets.com/Qo2SoGNQYSm57DxH6wiw "nest-17.png")

Indeed, we do have access. Let’s now change the role for our user to `Manager` and see if we suddenly lose access.

 ![nest-18.png](https://media.graphassets.com/bQm0XhdTRdGwwiNSjhxL "nest-18.png")

 ![nest-19.png](https://media.graphassets.com/L81cjHUSHG5b0QAyvd2D "nest-19.png")

 ![nest-20.png](https://media.graphassets.com/NcRkHkk9TMigxg2N3ui1 "nest-20.png")

Alright, our user is now a manager, so let’s navigate to the endpoint path and see.

 ![nest-21.png](https://media.graphassets.com/EDoy6gXQeGY1ArnXxyxw "nest-21.png")

Woops! It looks like the access has been taken away from us. That’s it! It’s as simple as that :)

Next time you need to protect an API endpoint in Nest.js, it will be a breeze. Learn more about [Permit](https://permit.io "https://permit.io") — or access the whole code repository for this project [here](https://github.com/filipermit/demo-projects/tree/main/nestjs-api-endpoint-guard "https://github.com/filipermit/demo-projects/tree/main/nestjs-api-endpoint-guard").