JSON Web Tokens


Basic Setup

For bare bones waterlock on a fresh installation of Sails, simply run the following

npm install waterlock
npm install waterlock-local-auth
./node_modules/.bin/waterlock generate all
sails lift


After running npm install waterlock, to get up and running fast we've provided you some nice generators to create the necessary files needed that make Waterlock work. The executable script provided with Waterlock ./node_modules/.bin/waterlock gives you all the power you need to generate the different components of Waterlock. To skip the boring stuff and get going simply run the command waterlock generate all.


Waterlock generates a config file at /config/waterlock.js this file is used to set up many options and features in Waterlock. Here is a brief overview on the options.

  • baseUrl - this is the URL your app resides at, used in password reset urls
  • autheMethod - the npm package name for the chosen authentication method or an array of methods
  • jsonWebTokens - object containing information on how the jwt's should be constructed
    • secret - the secret used to encrypt the token, CHANGE THIS VALUE!
    • expiry - object containing information on expiry these are passed to moment.js add function
    • audience - the jwt aud claim a good choice is the name of your app
    • subject - the jwt sub claim
  • postActions - Lets waterlock know how to handle different login/logout attempt outcomes.
    • login - post login event
      • success - custom DSL on how to route the successful request see config template for more details
      • failure - custom DSL on how to route the failure request see config template for more details
    • logout - post logout event
      • success - custom DSL on how to route the successful request see config template for more details
      • failure - custom DSL on how to route the failure request see config template for more details


The Attempt model tracks user login attempts.

user belongsTo relation, the user account that was trying to be accessed.
boolean if the attempt allowed a user to login.
string the ip address the attempt came from.
string the port the attempt came from.


The Auth model is used to hold all information needed for the chosen auth method. The base Auth model looks like the following.

user belongsTo relation, user that owns this Auth object.


The Jwt model tracks the tokens that have been distributed, how many times the given token was used, and if it has been manually revoked.

string the encrypted json web token.
use hasMany relation describing how many times this json web token was used.
user belongsTo relation describing which user this token was issued to.
boolean if this Jwt has been manually revoked.


The Use model described how many times a Jwt was used.

string the ip address the from which the token was used from.
jwt belongsTo relation, the Jwt that was used.


The User model

attempt hasMany relation, tracks login attempts.
jwt hasMany relation, the Jwt's issued to this user.
auth hasOne relation, the auth object for this user.

The Session

Waterlock uses the req.session express object to hold various information about the user.


This is a boolean value, used to indicate if this user has successfully authenticated


This is the authenticated user object.


Authentication itself is handled via modular libraries, making Waterlock more lightweight. The current auth libraries are listed below.

Method Library
Local Auth waterlock-local-auth
Twitter Auth waterlock-twitter-auth
Facebook Auth waterlock-facebook-auth

That's cool but how do i use them?

Glad you asked, simply run npm install with the chosen library then configure it in your waterlock.js file. As to the individual configurations see the README file of the chosen library. If your use case isn't solved by the libraries above please open a bug report and request it!


Before diving in and using your Jwt's you'll need to configure them. This is done via the waterlock.js file located in your Sails config folder. If you used the Waterlock generator then you'll already have that file along with default values. You will still need to modify them so crack it open and you should see the following.

  secret: "this is my secret",
    unit: "days",
    length: "7"
  audience: "app name",
  subject: "subject"


This is the value used to encrypt the Jwt's


This is an object containing information on when the tokens should be expired after they are issued. These values are passed to the Moment.js add function.


This is the aud claim of the Jwt. Typically this can simply be the name of your app.


This is the sub claim of the Jwt.

Requesting Tokens

Your user can request tokens, once they are authenticated, by navigating to the following URI /user/jwt. This will return a JSON response containing the JSON Web Token and it's expiration date, (which is configurable as shown above.) If the user does not have an authenticated session open a token will not be created and instead the server will respond with res.forbidden.

Token Policy

So you have your tokens configured and you can request them, but they aren't doing any actual securing of resources yet. To do this you can use the hasJsonWebToken.js policy that was generated by using the Waterlock script. This is a simple policy that allows your user to request access to a resource by providing the access_token (the jwt) attribute either as a GET or POST parameter. This is applied just like any other Sails policy. So you can check out their documentation to learn more.

How does it work?

Since sails currently has no official support for 3rd party libraries like Rails gems; Waterlock works by hooking into your model and controller files adding the functionality needed. When Sails starts officially supporting 3rd party libraries this might change. This allows you still have access and override the Models/Controllers Waterlock uses to work without having to dive into the module.


You can override or add to any of the default attributes/actions Waterlock uses just by dropping them in as if Waterlock was not there.

/* /model/User.js */
attributes: require('waterlock').models.user.attributes({

  /* e.g.
  nickname: 'string'


This allows you to keep control of your model/controller.

For even more customization check out our new api section