What we're trying to build

Our application shall have a User model with a name, an email and a password. There'll be a Post endpoint to create a User and this endpoint would be unauthenticated; anybody should be able create a User.
Also, we'll need to create another POST endpoint to sign the User in. This endpoint will verify that the user exists in the database and that the password is correct, and it shall respond with the User object and her/his authentication token.

This token is used to authenticate further requests. The token must be present in the header of any request that our API receives, in the form Authorization: Bearer token.

Lastly, we'll have another endpoint that lets a User edit it's profile.

Requirements

Plain password should not be saved in the database.

Password should be encrypted.

token should expire after some time, forcing the User to login again.

The endpoint that lets a User edit it's profile must be authenticated.

This endpoint must also not let a User edit another User.

The above is a (non-exhaustive) list of some of the things that need to be present in an authentication system.

Let's Code

Create a new API only Sails.js app using sails new auth-example --no-frontend.

Also, let us turn off blueprints for this example. In /config/blueprints.js

The above code is pretty straightforward except for a couple of things:
- columnName: "encryptedPassword". Remember our requirements? We’re not meant to save the actual password to the database but an encrypted version. What that line of code does is to specify that the column name in the database for that particular attribute should be encryptedPassword and not the default password. As for actually encrypting the password and saving that to the database, we’ll be getting to that soon.
- toJSON: Here we’re overriding the function that converts our model into a JSON response and deleting the password from that object. We don’t want the password (encrypted or not) to show up in our responses.

To handle encryption, we’ll make use of a library called bcrypt. You can read more about it here.

npm install bcrypt

Add var bcrypt = require("bcrypt") to the top of your user.js file.
Now, We’re going to make use of Sails model Lifecycle callbacks. “Lifecycle callbacks are functions that are automagically called before or after certain model actions.”

The above code simply creates an encrypted hash from the actual password and replaces it.

“Calling cb() with an argument returns an error. Useful for canceling the entire operation if some criteria fails.”

To round up this User model, we’re going to create one more fucntion called comparePassword.
It shall be a Promisified function that will resolve when the password matches the argument passed and reject when it doesn’t.
Bluebird is the Promise library we’ll be using and to do that, we need to npm install bluebird.

JSON Web Token

According to jwt.io -
“JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.”

To elucidate, a JSON Web Token is a string:
1. That carries all information within itself. This means that when a JWT is decoded, the result is a JSON Object with all the information that needs to be transferred.
2. That can be used to verify the sent data was actually created by an authentic source.

From the above, it’s clear that JWTs are perfect authenticating a user.

To make use of JWTs, we are going to create a simple Service that abstracts the functionality we want. Thankfully, this is easy, thanks to the jsonwebtoken node module.

It is important to note that it is bad practice to include your secret in your code and hence; version control. Except it’s a development secret (that your collaborators can use to test), then you can do exactly what’s in the code above.
In production, we would have an environment variable TOKEN_SECRET that store the actual production secret.

We used lodash to manipulate arrays, so you’ll need to npm install lodash first.

We used a certain ResponseService to format our request responses. There’s a previous post that’s short which explains how to write this service.

The rest is pretty straightforward, we first check if the confirmPassword parameter matches the password. Then we strip the request parameters of anything that isn’t in allowedParameters. We then create a User using Sails.js/Waterline queries and their in-built Promise support. Finally we issue a JWT and add it to the response object as token.

To complete the sign up flow, we add a route to /config/routes.js/

module.exports.routes = {
'post /signup': 'UserController.create'
};

This simply means that any POST request to the /signup endpoint will execute the create function we just made.

To test, fire up your Sails app with sails lift and send a POST request with Postman to see if your User gets created.