Per popular request, let’s now talk about the big bogeyman that scares all the new devs – authentication. Authenticating old fashioned websites used to be pretty simple and usually used domain cookies and server sessions, but nowadays that is not a very viable strategy because you usually need multiple clients accessing your API – web, mobile, 3rd party etc. Additionally, nowadays for scalability sake, API’s are preferred to be state-less – the server doesn’t preserve user state which means there can be no server session. This is why the dominant strategy has become OAuth2 and is used for Google’s and other industry leaders’ public facing API’s.
Authentication and authorization are big and sensitive topics which have been the subject of many books. This is a small and limited example and should be treated as such. It is by no means a full blown solution for enterprises with sensitive materials. There are many extensions and alterations that can be done to make this example better, but I could only fit so much in the scope of one article. The most obvious extension is that in a real world scenario the tokens need to be saved in the database and tracked and validated that way. I will expand on this in a future tutorial.
What is OAuth2?
It is the successor of OAuth of course. But really what is it? It was pretty mysterious to me, until I got linked to the actual draft by the OAuth Working Group where it is defined as:
The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf.
The 3rd party wording is a bit confusing. Why are we using a strategy for 3rd party auth? Since most engineers choose to not have 1 monolithic project, but break things up into multiple services and clients, your clients essentially end up being considered 3rd party as far as your API’s are concerned and different API’s can talk to each other, also being treated like 3rd party.
Visually in a scenario which allows refresh tokens, this looks like this:
The tokens which you see on the chart are JSON Web Tokens (JWT). The client requests authorization from the authorization server, if credentials are correct, it is granted an access token and a refresh token. Further requests from the client to the API must include this access token in the header. If the token is present and valid, the resource server responds with the desired resource, otherwise it returns an error. When the access token is set to expire, the client sends the refresh token and if it is valid, the server responds with a new access token.
* Keep in mind that there are certain complexities which are omitted from this chart, for example user roles and security level for resources – should some be only read by the owner, should all users be able to read them, in either case, only the owner and an admin should be able to edit and delete a resource. This is implied by the naming ‘authorization server’, but it’s not explicitly explained. We’ll discuss taking care of that in a future tutorial.
Now that the theory is somewhat clear, let’s see how we can implement this with code in the SANE stack. As always we use the “How To SANE” project as our demo.
3rd Party Modules
All this is pretty complex and prone to errors especially for developers new to it. Abiding by all the protocol clauses can be quite tedious, but fear not, there are very helpful modules to the rescue. I used 3 in particular which were designed according to the protocols for OAuth2 and JWT. Namely ‘jsonwebtoken’ and ‘express-jwt’by Auth0 for the server and Ember Simple Auth by Simpl Labs for the client. These modules are open-source, free and take care of the heavy lifting to achieve this authentication strategy. Here is what each of them does:
jsonwebtoken takes care of issuing and verifying json web tokens according to the protocol of the work group.
express-jwt is a middleware for express which extracts the token from the header and validates it, if it is found to be valid, it attaches the logged in user as the req.user object, so further middleware know which user is logged in.
ember-simple-auth is the client implementation and it does quite a bit for you on the client side – it maintains a client session in local storage which contains the token, when it expires and what user is logged in. Using that it creates a session object in browser memory which is available to ember from anywhere and can be used to alter the app’s behavior based on whether a user is logged in or not. It also provides an ‘protected route’ mixin which allows you to bar visitors who aren’t logged in from seeing protected areas of your app. Ember-simple-auth also has a renewal scheduling mechanism, it reads the expires_in value the server sends it when obtaining a token and attempts a renewal when the time comes so the user is not booted when the token expires.
You can find out how to install and use these modules in their according github repos, the node ones are as simple as a npm install and a require, while ember-simple-auth also takes a generate command and then certain mixins have to be extended and you are good to go.
Our own code
With all these powerful and convenient modules, our code ends up quite minimal. The bulk of it ends up being in our AuthController in sails where we have 2 endpoints, login and logout. The login point is the interesting one and the logic in it behaves like the chart above:
If a request is type password and has user credentials we look for that user and password combo in the database and if they are valid, we issue an access and renewal token and respond to the client with them. They are automatically stored in local storage by Ember Simple Auth and from then on our client behaves accordingly – like that user is logged in. Further requests sent by Ember contain a Authorization header which starts with “Bearer “ and then contains the encrypted token.
If a request is type renew, the logic takes the renew token and compares it to the access token it came with and if they are found to contain the same user and expiration dates, new tokens are issued with an expiration date further in time.
We configure Ember Simple Auth to use this endpoint in the Ember environment config – the keys having to do with simple auth. It is used for both issuing and renewing tokens automatically.
Next we have to configure sails to police the end points we’d like to protect. We make a hasToken policy which screens for incoming tokens in server/api/policies. It uses express-jwt and if it finds a valid token on the request it attaches the user to the request. If not, it returns a 400 error to the client. To specify which routes should be using this policy we go to server/config/policies and specify that all routes (*) should be run through the hasToken policy, except the Users Controller and the Auth Controller. This way to get anything out of the API you need a token, but you can make a new user or login without having a token and thus obtain one.
This is it for now. In a future tutorial we will explore authorization – how to save tokens in the database and validate them that way and how we can implement user roles and authorization levels for resources for each role.