Implement authorization and access control in an Express application

Published by Adejoke Haastrup on October 29, 2024
Implement authorization and access control in an Express application

Authorization and access control in Express

When building web apps, one of the important factors you should consider is how users will access various parts of your app. It is best practice to manage user permissions and access by restricting or granting access to certain application areas. In this post, we'll look at how to use Cerbos PDP (Policy Decision Point) to establish role-based access control (RBAC) in an Express application.

Getting started with Express and understanding Cerbos PDP (Policy Decision Point)

If you're familiar with Node.js, you've probably heard of Express. Many engineers opt to use Express, a Node.js framework, for developing JavaScript web apps. Cerbos PDP can be described as an engine for authorizing access to different parts of your app based on certain rules and policies you set.

Introduction to Role-Based Access Control (RBAC)

RBAC is all about assigning permissions to specific roles rather than individual users. Once roles are defined, users are assigned to these roles based on their responsibilities.

Understanding roles, permissions, and users

Let's say for example, you are building a learning management system. This will call for properly defined roles in your web app.

  • Roles: Representing a users function within a system. In our LMS example, to define a role you need to identify all the expected roles in your app E.g super admin, admin, users.
  • Permissions: Now that you have well defined roles, you have to grant specific privileges to the roles. For example only a super admin can upload and delete videos.
  • Users: Individuals on the app who are assigned predefined roles based on their specific responsibilities.

How-To guide: Practical RBAC implementation in Express with Cerbos PDP

Following our LMS example, we are going to build a sample project to demonstrate the implementation of RBAC in Express with Cerbos PDP.

Development environment setup

Before we begin, there are a few prerequisites you need to have in place. Please ensure that Node.js, Express, and most importantly, Cerbos PDP are installed on your system.

Node.js and Express

Install Node.js for your platform (we recommend LTS) and verify the installation by running the following command in your terminal:

node -v

Once Node.js is installed, install Express as well:

npm install -g express

Cerbos

Install the Cerbos PDP for your platform, and ensure that the binary is in your $PATH (or run it from the extracted location):

Once installed, test it to make sure that it can execute:

cerbos --version

Sample LMS to demonstrate RBAC

Once you're confident that Node.js, Express, and Cerbos PDP are installed, you can start a new project running these commands

mkdir lms-cerbos
cd lms-cerbos

This will create a new folder called lms-cerbos and navigate into it.

Next, initialize a new Node.js project:

npm init -y

Install all required packages

Install the necessary packages, including TypeScript and Axios:

npm install axios dotenv
npm install --save-dev typescript ts-node @types/node @types/express

Initialize a TypeScript configuration file:

npx tsc --init

Cerbos PDP setup

Configure the Cerbos PDP by creating a basic policy file that defines roles and permissions. Create a cerbos directory and add a policies sub-directory.

Create a policy file resource.courses.yaml in the policies/ directory:

# policies/policy.yaml
resource: "course"
version: "default"
roles:
  - id: "super-admin"
    grants:
      - actions: ["create", "upload", "delete"]
        condition:
          match:
            resource: "course"
  - id: "admin"
    grants:
      - actions: ["update", "edit"]
        condition:
          match:
            resource: "course"
  - id: "student"
    grants:
      - actions: ["view"]
        condition:
          match:
            resource: "course"

Roles and permissions

Create a roles.ts file to define the roles and their permissions:

// src/roles.ts
export const roles = {
  "super-admin": ["create", "upload", "delete"],
  "admin": ["update", "edit"],
  "student": ["view"],
};

Routing

Now we can set up routing in Express, where we enforce RBAC using Cerbos.

// src/index.ts
import express, { Request, Response } from "express";
import axios from "axios";
import dotenv from "dotenv";
import { roles } from "./roles";

dotenv.config();

const app = express();
app.use(express.json());

const cerbosURL = process.env.CERBOS_URL || "http://localhost:3592/api/check";

interface User {
  id: string;
  roles: string[];
}

app.post("/course_action", async (req: Request, res: Response) => {
  const { user, action } = req.body as { user: User; action: string };

  const cerbosRequest = {
    requestId: "1",
    actions: [action],
    resource: {
      kind: "course",
      attributes: {
        owner: user.id,
      },
    },
    principal: {
      id: user.id,
      roles: user.roles,
    },
  };

  try {
    const response = await axios.post(cerbosURL, cerbosRequest);
    const isAllowed = response.data.result[0].actions[action]?.isAllowed;

    if (isAllowed) {
      res.status(200).send("Action permitted");
    } else {
      res.status(403).send("Action forbidden");
    }
  } catch (error) {
    console.error("Error communicating with Cerbos PDP:", error);
    res.status(500).send("Internal server error");
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Testing out our sample app

Compile and run the application:

npx tsc
node dist/index.js

💡 You can test the application on Postman by sending POST requests to the /course_action endpoint with different roles and actions.

Sample request:

{ 
  "user": {
    "id": "user1",
    "roles": ["admin"]
  },
  "action": "edit"
}

Expected Responses:

  • 200 OK if the action permitted.
  • 403 Forbidden if the action is forbidden.

Conclusion

From this article, you've learned the importance of roles and permissions. You can also see in our example how we used Cerbos to enforce RBAC for an LMS. The super-admin, admin, and student roles are defined in the Cerbos policy file with their respective permissions for the course resource. The Express app communicates with Cerbos to check if a user is authorized to perform a specific action on a course, ensuring that only the appropriate roles can create, upload, delete, update, edit, or view courses.

Book a free Policy Workshop to discuss your requirements and get your first policy written by the Cerbos team