ACL express middleware implementation I come to see you to help me improve an express middleware that allows you to control access resources by checking the rights of the user.
The following code is supposed to be as generic as possible so that it can easily be added to another project.

But I have doubts both on its genericity and the clarity of its prototype, I let you judge :)

acl.ts

export let config: ACLConfig = {
  userField: 'me',
  roleField: 'roles'
};

export function isAllowed(roles: String[], ...cbs: Function[]) {
  return async function (req, res, next) {
    let allowed = false;
    let user = req[config.userField];
    if (!user) throw new APIError('ACL module cannot find req.{{userField}}', APICodes.ACL_INTERNAL_ERROR);

    let userRoles = user[config.roleField] || '';
    userRoles = userRoles.split(',');

    if (roles &amp;&amp; roles.length) {
      for (let role of roles) {
        if (userRoles.indexOf(role) !== -1) return next();
      }
    }

    if (cbs &amp;&amp; cbs.length) {
      for (let cb of cbs) {
        if (cb(req) === true) return next();
      }
    }

    throw new APIError('You do not have the required privileges', APICodes.AUTH_ACCESS_FORBIDDEN, HttpStatus.UNAUTHORIZED, true);
  }
}


must be used like this

route('/...').all(verifyToken, isAllowed(['staff, admin'], policies.isMyArticle))

maybe this following prototype is better ?

isAllow(...args: String | Function)
isAllow('staff', policies.isMyArticle, 'staff');
The code you've provided is fairly thin and so there's not to much to pick at here, however, I think your checks on roles and cbs can be simplified using Array.isArray(), because the for of iterator cannot iterate an empty array.


if (roles &amp;&amp; roles.length) {
  for (let role of roles) {
    if (userRoles.indexOf(role) !== -1) return next();
  }
}



can be transformed to:

if (Array.isArray(roles)) {
  for (let role of roles) {
    if (userRoles.indexOf(role) !== -1) return next();
  }
}


Although I think these checks would be better moved up and for you to return a 500 Server Error if roles or cbs aren't arrays.

In the same block of code you have indexOf(role) !== -1, which was simplified to .includes(role) in ES6.

The only other thing that comes to mind is the userRoles.split(',') call, because, if userRoles isn't a string, it'll raise an exception. However, that would depend on how malleable your database / validation is.

Additionally, your second suggested prototype has way more confusing usage than your implementation, I would stick with what you've created.