DEV Community

Petar Prokopenko
Petar Prokopenko

Posted on

NodeJS express ACL architecture

Recently I started working on nodejs server which is built using express framework. While I was developing server I came across a lot of challenges. One of those challenges was ALC.

For those who don’t know what ACL is, ACL stands for access control list. Just like the name says it is access control list, and it is a way to limit user to use specific resources. For example: admin can read, write and delete countries and the only thing users can do is read countries. Pretty Simple right?

For the architecture design I could have gone online and find the best one and I will be set, but that doesn’t sound like fun.

Solution must meet these criteria:

  1. Modular
  2. Easy to change and maintain
  3. optional: future profed

So I started thinking and finding the best solution.

After a couple of hours of thinking I came to this solution:

    [
        {
            route: '/api/country',
            methods: {
                get: ['user', 'admin'],
                post: ['admin'],
                put: ['admin'],
                delete: ['admin']
            }
        }
    ]

This solution was not good because when you need to change permission for the user by role it will be confusing and hard to read when you have large amounts of them. I liked how HTTP methods are in one object and kinda easy to spot.

The next intercession of the previous design looked something like this:

    const accessByRole = {
        admin: {
            get: ['/api/country'],
            post: ['/api/country'],
            put: ['/api/country'],
            delete: ['/api/country']
        },
        user: {
            get: ['/api/country'],
            post: ['/api/another-route']
        }
    };

This version now fixes readability of the resources by user role but as you can see now resource URL has been repeated many times. That is bad because when you change that resource than you need to search all files so that you can also change things there. That is not good, because you will lose too much time trying to find them all and update them which is not very productive. With that in mind and also with two roles which have the same urls there is a case that they can use. For that case this is not good. On to the drawing board we go.

After a quality sleep and rest I got back to it. Decided to go with good old array to help me solve some issues. The final design looks something like this:

    const moduleAccess = [
        {
            roles: ["roles.ADMIN"],
            method: {
                get: ['/api/country'],
                post: '*',
                put: '*',
                delete: '*',
            }
        },
        {
            roles: ["roles.USER"],
            method: {
                get: ['/api/country'],
                post: ['/api/country'],
                put: ['/api/country'],
                delete: ['/api/country'],
            }
        }
    ];

There she shines. This version fixes multiple roles and I kept the methods object. Like we noticed in previous design url where there was repeating which was not good. I found solution where I have separated file for resource URL. That file is in use for routes and acl. That way url were not repeating and you have one place for all the routes in module. I’m considering putting routes in one JSON file for a whole project, but that is for another day.

This was my first tech blog post. What do you think? Please let me know what you think in the comments below.

Have a nice day and peace out guys!

Top comments (0)