CASL and Cancan. Permissions sharing between UI and API.
In authenticated apps, we often want to change what users can do depending on their role. For example, a guest user might be able to see a post, but only a registered user or an admin sees a button to delete that post.
Managing these permissions may become a nightmare for applications which are split into UI and API. Moreover if there’re 2 different teams that implement these parts, they very likely will end up creating logic which handles permissions on UI and API separately. So, changes in back-end permission logic will require changes on front-end and vise-verse.
This increases delivery time and makes applications to be prune to bugs. So, what is the solution for this?
Whenever possible, define permissions on server side and share them with client side. This approach works very nice if you use Node.js because you can use CASL on both sides and easily transfer rules using JWT token as an example.
First time you’ve heard about CASL? You may want to read “What is CASL?”.
I created an example which shows how to integrate Rails 5 based API with Vue based UI. This is a simple blog application which allows to manage articles, login into app and logout.
There is not much to explain in server app. This is just a basic Rails application which renders JSON in response to requests. All authorization logic was done using
load_and_authorize_resource controller helper function.
Session management is stateless, based on JWT token. That token contains only
user_id field. To login, client needs to send POST request to
password. In case of successful response, server returns JWT token and a list of rules compatible with CASL format.
This is the response for user with role “member”:
This response tells that user can read everything (i.e.,
read all), can manage
2 and can read and update
id = 2. You probably already understood that
2 is an id of logged in user. So, in simpler words he can manage own articles, update own profile and read everything else.
Cancan stores rules differently from CASL, that’s why I added
to_list method into
Ability which creates an array of rules that CASL can consume.
CASL is shipped together with complementary package for Vue. This package adds
$can method into all Vue components and that makes possible to check permissions easily in templates. For example:
This app uses Vuex to manage local state. All requests to REST API a made through actions in
Vuex.Store. Also there are few plugins and modules which you can find in
src/store folder but the most interesting for us is
That plugin fills
Ability instance with rules when user login and clears it on logout.
In the code above, I create and export an empty
Ability instance (this instance will be used later as well). Then I create a Vuex plugin which subscribes to store changes. When
createSession (i.e., user login) action is committed, ability is updated with provided array of rules and on
destroySession (i.e., user logout), ability is reset to read-only mode.
And that’s it!
Now client side and server side permissions system are connected and when you change rules on API, you will not need to change code on UI.
Looking for more?
Read documentation and other articles about CASL:
- Official Documentation
- Vue ACL with CASL
- Managing user permissions in React app
- Permissions in Aurelia app
- Authorization in Expressjs app
- Easy API Authorization with CASL and Feathers
If you like CASL, ⭐️ Star it on GitHub and share this article with your friends.