How to Create an Authorization Middleware for Fastify
Published: 2023-03-24 07:22:06

---
title: How to Create an Authorization Middleware for Fastify
published: true
date: 2023-03-24 00:00:00 UTC
tags: 
canonical_url: https://www.permit.io/blog/how-to-create-an-authorization-middleware-for-fastify
---

Fastify has gained popularity among developers as a Node.js API/web framework due to its reputation for being fast, modular, scalable, and well-structured. It is also compatible with modern architectures such as microservices and serverless. Its optimized performance for these architectures has made it a preferred choice for many developers.

One of the benefits of using Fastify is the plugin system which allows you to easily add functionality to your API routes. This allows you to maintain the ‘separation of concerns’ principle, which prevents the mixing of plugin functionality with the business logic of your application. Thus, you can seamlessly add authentication, error handling, billing, and more services to your application using plugins.

One of the critical aspects of any modern application is  **authorization**. No one wants their application’s users to be able to read data that does not belong to them or perform operations they are not allowed to. This requires a granular access control system that checks what users can do and enforces it.

When it comes to authorization, many applications mix the permissions logic with the application logic, [<u><strong>which is not a good idea</strong></u>](https://www.permit.io/blog/four-mistakes-you-make-when-building-permissions#2-mixing-up-app-logic-and-authorization "https://www.permit.io/blog/four-mistakes-you-make-when-building-permissions#2-mixing-up-app-logic-and-authorization"). When these two logic sets are combined, they inevitably grow and become increasingly complex, turning any future effort of separating, editing, updating, or upgrading them into a nightmare. Authorization, the same as authentication, requires to be managed separately from our application logic. 

This guide demonstrates a middleware plugin which helps you implement a granular access control system into Fastify applications. We will use Permit.io’s cloud service to configure the proper permissions model, and then demonstrate how it can be seamlessly added to any kind of Fastify application. This will allow a proper enforcement model for your application users.

## Demo Application

To demonstrate the Permit.io service and its Fastify plugin for authorization, we created a demo blogging platform with the relevant Fastify APIs. See the code below:

``` typescript
require('dotenv').config();

import Fastify from 'fastify';
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";

// Create server
const server: FastifyInstance = Fastify({ logger: true });

// Mock handlers
const mockPublic = async (_req: FastifyRequest, _reply: FastifyReply) => ({ hello: 'public' });
const mockPrivate = async (_req: FastifyRequest, _reply: FastifyReply) => ({ hello: 'private' });
const authenticate = async () => ({ hello: 'authenticate' });

// Scoped private routes
const privateRoutes = async (fastify: FastifyInstance, _opts: any) => {
    // Mock authentication
    fastify.register(authenticate);

    fastify.post('/post', mockPrivate);
    fastify.put('/post', mockPrivate);
    fastify.delete('/post', mockPrivate);
    fastify.post('/comment', mockPrivate);
    fastify.put('/comment', mockPrivate);
    fastify.delete('/comment', mockPrivate);
    fastify.post('/author', mockPrivate);
    fastify.put('/author', mockPrivate);
    fastify.delete('/author', mockPrivate);
};

// Scoped public routes
const publicRoutes = async (fastify: FastifyInstance, _opts: any) => {
    fastify.get('/post', mockPublic);
    fastify.get('/comment', mockPublic);
    fastify.get('/author', mockPublic);
}

// Register scoped routes
server.register(privateRoutes);
server.register(publicRoutes);

// Start server
(async () => {
    try { await server.listen({ port: 3000 }); } catch (err) {
        server.log.error(err);
        process.exit(1);
    }
})();
```

For the purpose of this demo, we have implemented a mock authentication plugin (registered as a mock function in the code). 

We separated routes into public and private ones and protected the private ones with the mock Authentication plugin. [Permit.io](https://www.permit.io) works with every authentication method - so you can integrate it with any authentication method you prefer.

To follow this tutorial, we are recommending cloning the source code to your local machine, and run `npm i && npm run dev` so you can see it in action running on your local environment at port `3000`.

You can clone it from here (remove the branch to get the final version of the tutorial).

```
git clone -b tutorial git@github.com:permitio/permit-fastify-example.git
```

## Designing a Simple RBAC Permissions Model

When incorporating permissions into an application, it's important to design the model and be aware of which permissions should or should not be granted to users. To do this, we need to consider three entities: Who the user is (Their  **Identity and Role** ), What  **Resources** are we monitoring access for, and which  **Actions** can be preformed on that resource. The combination of these entities is called a  **Policy**. 

With those entities in mind, we can map our application into  **conditions** and  **policies** to reflect the permissions we want.

Let’s examine our demo blog’s APIs. 

- **Roles** can be assigned to  **authenticated users** (Admin, Writer, Commenter).
- **Actions** can be paired (to simplify the process) with  **HTTP methods** (Get, Create, Update, Delete, Patch).
- **Resources** are the different  **endpoints** we want to manage access for (posts, authors, comments, etc.)

By mapping them all, we can get the following table:

| Role | Resource | Action |
|---|---|---|
| Admin | Post | Get |
| Writer | Author | Create |
| Commenter | Comment | Put |
| | | Delete |
| | | Patch |


Now that we have our basic outline of our roles, resources and actions, we can map the desired allowed conditions (Following the least privilege principle) of the model as follows: 


- **Admins** can perform **any actions** on  **any resource**
- **Writers** can  **create** ,  **update** ,  **patch** , and  **delete posts** , and  **get comments**
- **Commenters** can  **get** and **create comments**

## Configuring Permissions in Permit.io

Now that we have our model designed, let’s implement it! As we previously mentioned, we do not intent to incorporate the policy code as part of the API logic. To keep 

things clean, we want a separate service that allows us to define and configure the policies. This way, the service can focus on enforcing permissions, while the application code focuses on vital application logic.

[Permit.io](https://www.permit.io) is an authorization-as-a-service product that lets us configure and enforce permissions, keeping your code clean and controlling your application access. The tool has an extensive free tier, and is completely self service.

To configure the desired application permissions, let’s follow these steps:

1. Log in to Permit.io at [app.permit.io](https://app.permit.io/ "https://app.permit.io/")

2. After logging in, go to the Policy page and create the following roles:
![Create roles blog.png](https://media.graphassets.com/rl4unQM2SzSwNn5E8b7T "Create roles blog.png")
3. Continue by creating the resources with their actions:⁠
![Resources Blog.png](https://media.graphassets.com/Gurboi71RGTog7ZE21aA "Resources Blog.png")
4. Implement the desired conditions to the policy table by checking the relevant boxes.
![Policy editor blog.png](https://media.graphassets.com/lwNUckXwQZGMUcLp2Q9q "Policy editor blog.png")
5. We will finish the configuration by creating three users and assign them the relevant roles in the Users screen.
![Users blog.png](https://media.graphassets.com/QIW5E9rpT2GXf2Dhmbij "Users blog.png")

That’s it! Now that we set up our permissions, its time to connect them to our Fastify application.

## Enforce Permissions with the Fastify Plugin

To enforce the policy in our application, let’s do the following:

1. Grab the SDK code for Permit.io’s APIs from the application:
![saveAPI.png](https://media.graphassets.com/0aCsTw4YSmWvEa1p5vZG "saveAPI.png")
2. Paste it in your .env file in the following format.  
`PERMIT_SDK_TOKEN=<permit_sdk_token>`
3. Let’s now create a new plugin file. If you cloned our project, you can find the `authorize.ts` file in the `plugin` folder. If you are using your own project, do it in your desired plugin folder.
4. In the file we created, paste the following code. Look at this commented code, you’ll find a granular middleware that checks the permissions of the API requests by the request configuration.
    ```typescript
    import type { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from 'fastify';
    import { Permit } from 'permitio';
    
    // Initialize Permit SDK with token from the .env file
    const permit = new Permit({
      token: process.env.PERMIT_SDK_TOKEN,
      pdp: 'https://cloudpdp.api.permit.io'
    });
    
    export const withPermitMiddleware = async (req: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {
      const { headers: { user = '' }, body: attributes, routerPath, method: action } = req;
    
      // Take user from the header, in a real world scenario this would be a JWT token
      const identity = (Array.isArray(user) ? user[0] : user);
    
      // Split the path to get the resource type
      const type = routerPath.split('/')[1]
    
      // Build the resource object. If the request body is empty, we only need the type
      const resource = attributes ? { type, attributes } : type;
    
      // Check if the user is allowed to perform the action on the resource
      const allowed = await permit.check(identity, action.toLowerCase(), resource);
    
      // If the user is not allowed, return a 403
      if (!allowed) {
        reply.code(403).send({ error: 'Forbidden' });
      }
    };
    ```
5. Now that we have the generic middleware, we only have to paste the following code at the top of the private routes registry, just after the authentication plugin register.
    ``` typescript
    import { withPermitMiddleware } from './plugins/authorize';
⁠    
    ...
    // Add authorization middleware
    fastify.addHook('preHandler', withPermitMiddleware);⁠
    ...
    ```

Looking at the code, we can see the options object where we streamlined the auth header as the identity key, the URL to the resource name, and the action method. At this point, we have access control protection with Permit.io Fastify middleware.  
Let’s run our project with npm run dev and send a creating an author request with a writer user. This should result in the following error:

<video controls>
          <source src="https://media.graphassets.com/IKw1Tg8mSryrROMyvJcA"  type="video/mp4"></source>
          Sorry, your browser doesn't support embedded videos.
        </video>
## Evolve your Permissions with ABAC

In a real world scenario, it can be challenging to streamline our Identity, Resource, and Action to a flat list of Roles, Resource types, and Action names, as we did in our example. 

If, for example, we would like to have approval flow for content in our blog, and only allow approved writers to publish articles, disallow comments from a specific geolocation, or any other more granular limitations, simple RBAC will not suffice.  

Managing more granular permissions such as these require handling  **attributes** , which can be achieved through Attribute-Based access control (ABAC).

Let’s write the conditions we list above, but with more details on the attributes.

- **Admin** users can perform any **action** on any **resource**.
- **Writers** can **edit** , and **delete** posts but **create** only **unpublished posts**.
- **Approved writers** can **create** any kind of **post**.
- **Commenters** can **create** comments.

Adding attributes to an RABC model, thus essentially switching to ABAC is quite a complex task. Permit.io helps you to alleviate this complexity, as we can simply change our configuration to support the new permission model without any changes in the application code.   
A typical way to implement ABAC is using  **Resource Sets** and  **User Sets** —these sets are built from conditions that combine user and resource attributes. Let’s see how we can utilize these and configure these policies within Permit.

1. We start by configuring the attributes on the following resources. You can do this by clicking the three dots on the resource table in the  **Policy Editor** and then Add Attribute
![Resource attribute config blog.png](https://media.graphassets.com/sDIFnoOgTm6t2VAZ9Xxo "Resource attribute config blog.png")
2. Now that Permit.io is aware of our resource attributes, let’s create the conditions by creating `Resource Sets` in the  **Policy Editor**.⁠
![Resource set config blog.png](https://media.graphassets.com/LJtUXBM6Q9Orn2ZDxF4L "Resource set config blog.png")
3. To match the policy with user attributes, we need to configure user attributes as well. This can be done from the Users screen by clicking the `Attributes` tab and creating an approved attribute.
![Create user attributes blog.png](https://media.graphassets.com/xhSGr1ROq7JbAQQvm9GA "Create user attributes blog.png")
4. Let’s also add a new user in the Writer role that has the approved attribute in their profile. This will help us to check the ABAC policy later. To do so, just add a Writer role user, and then assign them the following attributes.
![Create roles ABAC.png](https://media.graphassets.com/PPfZBWu5RRStf8eCrwQG "Create roles ABAC.png")
5. Now that Permit.io is aware of our custom user attributes, let’s create the conditions by creating `User Sets` in the  **Policy Editor**.
![User Sets blog.png](https://media.graphassets.com/QSZspQWJRLD9wTDcqwt6 "User Sets blog.png")
6. You can now see new options in the policy table - let’s adopt the policy configuration to our newly defined conditions.
![Policy editor ABAC blog.png](https://media.graphassets.com/05N4WVJTKaNPK7zk0ilB "Policy editor ABAC blog.png")

Instead of rewriting our application code, the same middleware we created for our private routes will continue to enforce permissions with the new policy model configuration we assigned.

<video controls>
          <source src="https://media.graphassets.com/kzql6KRSQda6lJJUVonQ"  type="video/mp4"></source>
          Sorry, your browser doesn't support embedded videos.
        </video>
## What Next?

At this point, you should have a basic understanding of how to implement a basic authorization model into your Fastify application, enforcing permissions with single line of code. 

The next step would be to analyse the particular needs of your application, and implement a reliable permission model into it. As you saw in the article - it shouldn’t be very complicated. 

The plugin we created for this blog is available and ready to use - Just adapt it to your application’s factors in the relevant request fields, and your done.

If your organization already implemented an authorization model, and you want to learn more about how to scale it right, [<u>Join our Slack community</u>](https://io.permit.io/permitslack "https://io.permit.io/permitslack") where hundreds of devs and authorization experts discuss building and implementing authorization.