Skip to content

Instantly share code, notes, and snippets.

@mikermcneil
Last active July 11, 2019 09:48
Show Gist options
  • Save mikermcneil/50a2fd9ddf9df3881fae to your computer and use it in GitHub Desktop.
Save mikermcneil/50a2fd9ddf9df3881fae to your computer and use it in GitHub Desktop.
FAQ and best practices for using policies in Sails.js

Policies in Sails.js

Policies are additive. Anything you might do with policies, you could just implement in your custom actions directly. But they can make your life a lot easier.

When should I use policies?

Policies can be used like middleware, meaning you can do almost anything you can imagine with them. That said, our experience using Sails to build all sorts of different apps has taught us that policies are best used for one, very specific purpose: preventing access to actions for certain users (or types of users) where those actions are not accessible in the UI. That is, policies are best used like preconditions-- you can use them to take care of edge cases that are only possible by cheating the UI.

For example, imagine you're building an action called changePassword in your UserController. Its job is to take the new password that was provided, encrypt it, then update the database record for the currently-logged-in user to save the new encryped password. When you implement and test this action, your first inclination is to log in first. In fact, it's nonintuitive to check what happens if you're not logged in! This is a perfect example of where policies are helpful. You can implement your action to handle the cases that are actually accessible from your UI; then handle edge cases which are NOT trigger-able from the UI using policies.

In other words, instead of adding the following to the top of your action code:

  // Check that the request is originating from a logged-in user before we get too deep in the weeds.
  if (!req.session.myUserId) {
    return res.forbidden();
  }

You could implement a policy called isLoggedIn and apply it to UserController.changePassword in config/policies.js. The implementation of said policy might look like:

if (req.session.myUserId) {
  return next();
}
return res.forbidden();

Policy best practices

I used to have a very different stance on policies. However, working on countless Sails apps has taught me a number of rules of the road that, if followed, help prevent your app from becoming tangled and confusing. If you have been using Sails for a while, you'll notice that some of these suggestions are an about-face from what I suggested in the past. I'm sorry- I was wrong :/ I did my best to explain the why in each case, but please let me know if I missed something.

Don't look at parameters

Truly reusable policies should only look at req.session and the database- NOT at parameters! Relying on parameters makes your policy context-specific and only usable in very specialized circumstances. And in that case, why not just put the code in the relevant action(s)?

Nullipotency

Policies should be nullipotent-- that is, they should not set, write, or frankly "do" anything. In the past, I suggested the strategy of using custom properties of req (specifically req.options) to allow your policies to take on more responsibilities. But in practice, I've learned that this ends up causing more pain than it alleviates.

Policies shouldn't be a core part of your business logic

Policies are a great way to protect against edge cases that are not accesible in the UI. But they are not a good tool for structuring logic in your app. Using them this way makes them just as versatile as raw Express/Connect middleware-- and unfortunately it also makes them just as dangerous and developer-specific. If you use policies to help with queries, or create complex chain of policies to manage permission systems in your app, you are likely to create a code base that is very difficult for any other developer to understand.

@B-StS
Copy link

B-StS commented Apr 25, 2018

@mikermcneil
We are quite new to Sails JS.
We have a Sails app running locally inside our company’s network, which is still under development.
We made this SO post (https://stackoverflow.com/questions/49990040/sails-js-user-management-best-practice-2018) asking for the best practice for managing roles and policies, and now we just stumbled upon this FAQ.
As our knowledge of Sails policies comes from your Sails.JS In Action book, we were wondering if it still has the best examples to manage them because of what you say here.
Is the book still the best practice ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment