Drupal & Sails.js cooperation… is it the best option?

Touch4IT Team
Touch4IT
Published in
4 min readMay 23, 2018

We interconnected two independent systems (Drupal and Sails.js) to work together and it saved our time of front end development by using already fine-tuned and customizable CMS (Drupal). Since we had to use some business logic including realtime calculations, push notifications and easily consumable API for mobile applications, Sails.js framework gave us a solid base.

Drupal & Sails.js Cooperation

What the client wanted…

Our client asked us to develop application for educational system in which teachers can manage educational content of various types (images, voice records, videos, …), create assignments for students, monitor their progress and send reminders. Students can browse these materials with mobile application, answer questions in assignments and see own progress.

What we did…

Drupal was used for database, content, user interface, user accounts and user permissions and Node.js server held server-side business logic with Sails.js framework. As a connector between Drupal and Sails.js we used Waterwheel.js library.

The problem was that we needed to use user accounts from Drupal but holding an instance of Waterwheel library in each user’s session is not possible because of Redis cutting off functions and interfaces from it. Next problem was that Waterwheel starts OAuth authentication process every time an instance with username and password fields are present in configuration. It’s not acceptable for a user to wait a minimum of 3 seconds for each request. But in the Waterwheel’s source code we found out that the OAuth process will not start again if tokenInformation object with valid token is present. We forked the library, made a few optimizations and also implemented support for PATCH requests with JSONAPI. It’s available on our GitHub.

How was the implementation process?

Each Drupal’s node has its own Sails.js service file which sends requests to Drupal. Services are called from controllers.

To correctly connect Drupal with Sails.js, we instantiated Waterwheel instance in login(req, res) function in UserController and called services/User.getCurrentUser with that instance. As a result of Waterwheel library making an OAuth, tokenInformation object was added to the instance. Then we picked only that object and saved it into the user’s session.

To use saved tokenInformation object in next requests, we needed to create a policy “waterwheel” and allow it for all requests except login in policies.js config. Saved tokenInformation object is retrieved from session and added to the req object which can be later accessed as “req.waterwheel” — this is the user’s Waterwheel instance.

To obtain new tokens every time they have been refreshed, they need to be saved to session in responses.

We had to solve the problems with OAuth 2.0

We also encountered problems with OAuth authentication process because as OAuth 2.0 specification says: „refreshed access token can have the original scopes or fewer“.

Since our mobile applications are intended to be used by teachers and students, we have multiple roles sent in Waterwheel’s config with every request („roles“ = „scopes“ in OAuth). Drupal manages the situation because it assigns only roles that are valid for a user which is currently trying to authenticate.

Example: Waterwheel library sends request with 3 requested scopes („student“, „teacher“, „authenticated“) but student is not allowed to be „teacher“ so the authentication process omits one invalid role and assigns only two valid roles to the user’s token.

Problem starts when we try to refresh expired access token with refreshed token and all scopes. If one scope is invalid, OAuth 2.0 server will throw an exception. Because of that, we forked the OAuth 2.0 server library and changed that behavior so it will silently omit invalid roles without throwing exception. Along with that, we optimized its installation (included vendor) and added valid scopes to the response when receiving new token because we needed to know user‘s valid scopes in Sails.js code and because Drupal does not return user’s roles when request is made with JSONAPI, we needed to obtain roles from another source. The forked library is available on our GitHub.

The End of the Story…

By creating the Drupal-Sails.js connector we prepared fully operational boilerplate for our future projects in case we will need content management with customizable user interface and separated server-side business logic. Despite the fact we forked 2 libraries and slightly modified them, we didn’t violate any standard’s specification (e.g. OAuth) and we are able to update them from their original master branches.

--

--

Touch4IT Team
Touch4IT

We are product oriented app development company bringing innovations to the market. ➡ www.touch4it.com.