A flexible, string-based authorization middleware for Node.js/Express apps. Easily define access control using simple, readable expressions combining role and membership.
- Allow or deny access using compact permission strings.
- Supports nested conditions like role-based and membership-specific logic.
- Easy to plug into existing Express routes as middleware.
- Inspired by a simple DSL-style matching pattern.
Just copy permitTo function into your middleware file:
const { permitTo } = require("./permitTo");Make sure you also have AppError and messages.userRestricted configured to match your project’s error handling.
Each permission is defined in the form:
role(membership)You can combine multiple permissions with commas:
"admin,staff(employee),!user(basic),distributors(!basic)"admin: allow all users with roleadminstaff(employee): allow only staff withemployeemembershipdistributors(!basic): allow distributors exceptbasicones
!user(basic): deny users with basic membership!user: deny all users!(...): deny a condition globally
app.get(
"/dashboard",
permitTo("admin", "staff(employee)", "!user(basic)"),
(req, res) => {
res.send("Welcome to dashboard!");
}
);- It uses dynamic regex to match permissions from the user
roleandmembership. - Rules are recursively evaluated.
- Negation (
!) is used to define restrictions. - If no permissions are passed, access is granted by default.
req.user = { role: "user", membership: "basic" };
permitTo("!user(basic)"); // ❌ Denied
req.user = { role: "distributors", membership: "pro" };
permitTo("distributors(!basic)"); // ✅ Allowed
req.user = { role: "staff", membership: "employee" };
permitTo("staff(employee),!user"); // ✅ Allowed
req.user = { role: "user", membership: "premium" };
permitTo("user(premium),!user(basic)"); // ✅ Allowed- If no matching logic is defined for
roleormembership, access is allowed. - Invalid string formats won’t throw but might silently allow/deny—validate your patterns.
- The logic is customizable and extensible.
Ensure the following exists:
// ./appError.js
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
}
}
module.exports = AppError;// ./messages.js
module.exports = {
userRestricted: "You are not allowed to access this resource.",
};- Convert permit string into parsed object structure
- Add test cases with Jest or Mocha
- Add TypeScript definitions (optional)
- Allow dynamic field matching beyond role & membership (e.g., plan, team)
MIT
Crafted with logic and recursion by Shakib Ali @hamamagraphics – feel free to star ⭐ or fork 🍜 the repo!