The Permission Pass

Using Mongo, Express, Pug, and Node.js (with a bit of Socket.io)

Chris Johnson
The Squash and the Tomato
3 min readNov 27, 2017

--

Tip for you: saying you’re working on “permissions” doesn’t give anyone a fucking clue what you’re really doing. Trust me, I know from experience 😐.

If you’re new to permissions and looking to get a quick understanding of the main types of permissions in 5 minutes, this is for you.

Permissions

I can think of two types of permissions relating to software: authentication and user roles.

Authentication

Do you have the rights to access this?

Essentially, authentication permissions are login permissions and access permissions:

  • Login permissions questions whether a user has registered and is/not logged in.
  • Access permissions asks does the user have high enough authentication to access certain information.

Authentication can be handle “fairly” easily using tools like passport.js. For the most part, you can plug and play their social authentication strategies and have permissions up and running in about two hours (this also involves creating apps on each social platform’s developer page). To do this, you need to setup an app on a respected social platform with an authentication url and callback url.

User Roles

Where do you fall in the hierarchy of permission levels? Can you view, edit, or own that shit?

Essentially, user roles control what users are allowed to do in a given domain:

  • Does the user have high enough permissions to perform this action?
  • Does the user have high enough permissions to change other users’ permissions?

I recommend building you’re own methods for setting, managing, and checking user roles. For example, you can write a function to set a user’s available list performable methods and later, use those methods to manipulate list data, if permitted.

Squash Tomato

For Squash Tomato, I’ve already used passport.js to handle user authentication, but I needed a way of ensuring users couldn’t perform functions on lists they didn’t have ownership of (these lists were shared to them).

I’m using Pug to handle templating, which will disable any element corresponding to an action a user isn’t permitted to perform, but as a backup to a user changing a disabled attribute inside dev tools, I wanted to build a user role check into my code.

My solution

  1. A user performs an action.
  2. A function calling an API endpoint executes. The API contains a query parameter for the list item being modified, information needed to update the list item in the database, and a permission variable.
  3. If the permission variable is null, which means this API request is the first action a user has taken since loading the list page, the permission variable is set using a function that returns the user’s permission for the list visited.
  4. If the permission variable contains a string value equal to a permission level, permission checking and setting is skipped.
  5. As long as the permissions are valid, a controller performs the action a user request in step #1.

When I first came up with this solution, the controllers handling each request on the frontend (which call API endpoints) would check for permissions every request. Fuck that, am I right? Performance would completely dive at scale. So, I wrote a function that checks for a user’s permissions if and only if permissions is not already set from the client-side JavaScript (received from the API request). Regardless of whether the function has to retrieve and set permissions or bypass checking, the controller returns the permissions to the client-side JavaScript, which sets a global variable.

This is the important part. Each API request sends the global variable related to a user’s permissions. If that value isn’t null, the permission checking function doesn’t do shit. How is this a win? The only time you have to check for permissions is on the very first API request on page load, which reduces the time and demand of all requests following (in Squash Tomato, a user could make an API request 100 times before reloading the page).

What now

To implement this strategy correctly, I have to refactor EVERY single controller and function relating to list manipulation. This is a good thing, especially since I’m also able to make my client-side functions pure while I’m at it. Once I’ve refactored each function or controller method, I’ll begin using WebSockets to make changes interactive in real-time for concurrent users.

Let me know if you have any questions!

Follow my development process on twitter at @chrisjohnsoct.

--

--

Chris Johnson
The Squash and the Tomato

Full-stack Surgeon (Design, Vue, Node, mongoDB), knowledge seeker, world dominator, Harry Potter and anime addict, volleyball player, and unfiltered.