RBAC for express js

Role-Based Access Control (RBAC) is a common approach for implementing access control in web applications. In an Express.js application, you can implement RBAC by creating middleware functions that check the user’s role and grant or deny access to certain resources based on their role.

Here is an example implementation of RBAC middleware in Express.js:

// Define roles and their permissions
const roles = {
  guest: ['read'],
  user: ['read', 'write'],
  admin: ['read', 'write', 'delete'],
};

// Middleware function to check if user has permission
function hasPermission(role, permission) {
  return roles[role] && roles[role].includes(permission);
}

// Middleware function to check user's role and grant or deny access
function checkRole(role) {
  return function(req, res, next) {
    if (req.user && hasPermission(req.user.role, role)) {
      next();
    } else {
      res.status(403).send('Forbidden');
    }
  }
}

// Route that requires user to have "write" permission
app.get('/api/posts', checkRole('write'), (req, res) => {
  // code to handle request
});

In this example, we define the roles and their corresponding permissions as an object. We then create a hasPermission() function that checks if the user’s role has the required permission. Finally, we create a checkRole() middleware function that takes a role as a parameter and returns a middleware function that checks if the user has that role and grants or denies access based on the user’s role and the required role for the resource.

To use the checkRole() middleware in a route, we pass the required role as a parameter and use it as middleware before the route handler function. In this example, we have a route that requires the user to have the “write” permission to access it.

Note that in this example, we assume that the req.user object contains information about the user’s role. You may need to implement authentication and authorization logic to set this object in your application.

RBAC with multiple account level

RBAC can be extended to support multiple account levels by defining roles and permissions for each account level. For example, if your application has three account levels – regular user, premium user, and admin – you can define roles and permissions for each level as follows:

// Define roles and their permissions for regular user
const regularUserRoles = {
  guest: ['read'],
  user: ['read', 'write'],
};

// Define roles and their permissions for premium user
const premiumUserRoles = {
  ...regularUserRoles,
  premium: ['read', 'write', 'delete'],
};

// Define roles and their permissions for admin
const adminRoles = {
  ...premiumUserRoles,
  admin: ['read', 'write', 'delete', 'manage'],
};

// Middleware function to check if user has permission
function hasPermission(role, permission) {
  const roles = {
    regular: regularUserRoles,
    premium: premiumUserRoles,
    admin: adminRoles,
  };
  return roles[role] && roles[role].includes(permission);
}

// Middleware function to check user's role and grant or deny access
function checkRole(role) {
  return function(req, res, next) {
    if (req.user && hasPermission(req.user.role, role)) {
      next();
    } else {
      res.status(403).send('Forbidden');
    }
  }
}

// Route that requires premium or admin level access
app.get('/api/premium-resource', checkRole('premium'), (req, res) => {
  // code to handle request
});

// Route that requires admin level access
app.get('/api/admin-resource', checkRole('admin'), (req, res) => {
  // code to handle request
});

In this example, we define roles and permissions for each account level using objects. We use the spread operator to inherit roles and permissions from the previous account level, and add new permissions as required. We then define a hasPermission() function that takes the role and permission as parameters and checks if the role has the required permission. This function uses an object that maps account levels to their corresponding roles and permissions.

We also define a checkRole() middleware function that takes the required role as a parameter and checks if the user has the required role and level of access. We use this middleware function in the routes that require specific levels of access.

Note that you may need to modify the authentication and authorization logic to set the user’s role and account level in the req.user object. You can also define additional levels of access as required by adding new objects for each level and updating the hasPermission() and checkRole() functions accordingly.

RBAC; if same user have different roles in different accounts

In a scenario where the same user has different roles in different accounts, you can extend the RBAC model to include account-level roles and permissions. In this case, you would need to define roles and permissions for each account separately and check the user’s roles and permissions in the context of the account they are accessing.

Here is an example implementation:

// Define roles and their permissions for account A
const accountARoles = {
  guest: ['read'],
  user: ['read', 'write'],
  admin: ['read', 'write', 'delete'],
};

// Define roles and their permissions for account B
const accountBRoles = {
  guest: ['read'],
  editor: ['read', 'write'],
  manager: ['read', 'write', 'delete'],
};

// Middleware function to check if user has permission for a specific account
function hasAccountPermission(role, permission, accountRoles) {
  return accountRoles[role] && accountRoles[role].includes(permission);
}

// Middleware function to check user's role and grant or deny access for a specific account
function checkAccountRole(accountRoles) {
  return function(req, res, next) {
    if (req.user && hasAccountPermission(req.user.role, req.permission, accountRoles)) {
      next();
    } else {
      res.status(403).send('Forbidden');
    }
  }
}

// Route that requires admin level access for account A
app.get('/accountA/admin-resource', checkAccountRole(accountARoles)('admin', 'delete'), (req, res) => {
  // code to handle request
});

// Route that requires manager level access for account B
app.get('/accountB/manager-resource', checkAccountRole(accountBRoles)('manager', 'delete'), (req, res) => {
  // code to handle request
});

In this example, we define roles and permissions separately for each account. We then define a hasAccountPermission() function that takes the user’s role, the required permission, and the account roles and permissions as parameters and checks if the user has the required permission for the account they are accessing.

We also define a checkAccountRole() middleware function that takes the account roles and permissions as a parameter and returns a middleware function that checks if the user has the required role and permission for the account they are accessing. This function uses the hasAccountPermission() function to check the user’s roles and permissions in the context of the account.

Finally, we use the checkAccountRole() middleware function in the routes that require specific levels of access for a specific account. The req.permission parameter can be set to the required permission for the resource being accessed.

Note that you would need to modify the authentication and authorization logic to set the user’s roles and account for each request. You can also define additional accounts and roles as required by adding new objects for each account and updating the hasAccountPermission() and checkAccountRole() functions accordingly.

Leave a Reply