CASL and Cancan. Permissions sharing between UI and API.

Sergii Stotskyi
DailyJS
Published in
4 min readMay 15, 2018
CASL + Vue + Rails

With growing amount of devices, applications were split into 2 separate services: front-end (UI, what user sees and interacts with) and back-end (API, implies business rules). These 2 pieces may be written in the same language (e.g., JavaScript) or in different (e.g., JavaScript on UI and Ruby on API). That approach allows to write business rules ones and implement separate User Interfaces for each device type (e.g., Web, iOS, Android).

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?

Share Permissions

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.

Also it works seamlessly with Ruby’s cancan gem (unsupported, community created a fork called cancancan). Actually this gem was a big motivator for me to create CASL :)

First time you’ve heard about CASL? You may want to read “What is CASL?”.

Update: CASL 4.0 is released, see “CASL 4.0. What’s inside?

Integration Example

CASL + Vue + Vuex + REST API

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.

For those, who are interesting in the end result, check Vue app and Rails API repos

REST API

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 /api/session with email and 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 Article where author_id equals 2 and can read and update User with 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.

Vue app

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 src/store/ability.js.

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.

Later this plugin is connected into store via plugins property and that ability is re-exported and passed into Vue’s abilitiesPlugin.

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:

If you like CASL, ⭐️ Star it on GitHub and share this article with your friends.

--

--