Implementing a role-based access control (RBAC) system is essential for many web applications that require different levels of user permissions. In this article, we will explore a real-world example of building such a system using TypeScript and Express.js, a popular Node.js framework.

Prerequisites

  • Basic knowledge of TypeScript and Node.js
  • Experience with Express.js framework
  • Understanding of user authentication and authorization concepts

Project Setup

Start by creating a new directory for your project and initializing a new Node.js project:

mkdir role-based-access && cd role-based-access

npm init -y

Install necessary dependencies:

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

Create a tsconfig.json file for TypeScript configuration:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

Defining User Roles and Middleware

Define roles and create middleware to check user permissions:

// src/roles.ts
export type Role = 'admin' | 'editor' | 'viewer';

export const rolesPermissions: Record = {
  admin: ['create', 'read', 'update', 'delete'],
  editor: ['read', 'update'],
  viewer: ['read']
};
// src/middleware.ts
import { Request, Response, NextFunction } from 'express';

export function authorize(allowedRoles: Role[]) {
  return (req: Request, res: Response, next: NextFunction) => {
    const userRole: Role = req.headers['x-user-role'] as Role;

    if (!userRole || !allowedRoles.includes(userRole)) {
      return res.status(403).json({ message: 'Forbidden' });
    }
    next();
  };
}

Creating the Express Server

Set up the server and define routes with role-based access control:

// src/index.ts
import express from 'express';
import { rolesPermissions } from './roles';
import { authorize } from './middleware';

const app = express();
const PORT = 3000;

app.use(express.json());

app.get('/public', (req, res) => {
  res.send('Public Content Accessible to All');
});

app.get('/admin', authorize(['admin']), (req, res) => {
  res.send('Admin Content');
});

app.get('/edit', authorize(['admin', 'editor']), (req, res) => {
  res.send('Editor and Admin Content');
});

app.get('/view', authorize(['admin', 'editor', 'viewer']), (req, res) => {
  res.send('Content for All Roles');
});

app.listen(PORT, () => {
  console.log(\`Server is running on port \${PORT}\`);
});

Testing the System

Use tools like Postman or curl to test different endpoints by setting the x-user-role header:

curl -H "x-user-role: admin" http://localhost:3000/admin
curl -H "x-user-role: viewer" http://localhost:3000/admin

Conclusion

Building a role-based access system with TypeScript and Express.js is straightforward with middleware functions that check user roles. This setup can be expanded with real authentication mechanisms, database integrations, and more complex permission schemes to suit your application's needs.