Welcome again! If you reached this post from nowhere and don’t understand what all this is about, you can check out the previous posts:
- 1. Intro and Initial Setup
- 2. Setting up the Web Server
- 3. The Database: Setup
- 4. The Database: Connect and Config
- 5. The Endpoints
You can find the code for this tutorial in GitHub.
If you followed the steps from the previous posts your project directory structure should look like this:
If it doesn’t, please go back and check if you missed something from the previous posts.
RESTful API Security
It’s time to take care of a key point on our RESTful API: the security. We have our endpoints to manage users and tasks, but right now any client that knows where our API is running can access the endpoints. This is not safe, in the real world you’d want to control who has access to your API and you need to check with every request that it’s coming from a trusted source.
There are at least two security aspects you want to take care of when building an API: authentication and authorization. There’s always someone who doesn’t know the difference between these two, so here a one sentence explanation for both:
- Authentication: the action of identifying a user in your platform
- Authorization: the action of checking if whether or not the already authenticated user has access to a specific resource
So you can basically see it as a pipeline: request -> authenticate -> authorize -> response. First you check that the request is coming from a trusted source, and after that you check that the trusted source has access to the resource it’s trying to get from your system.
In our API authentication will be provided by a user/password sign in endpoint which will return back a JWT (JSON Web Token)
- more about this later on - that can be used to authenticate subsequent requests. The authorization will be simply handled by our controllers to do some basic checks like not allowing a user to see or change the tasks of other users.
For the purpose of this project we’ll only take care of authentication which is the most complex. Authorization won’t be covered here but I’ll just say that it can be achieved easily with database checks in the simplest implementations and user roles management in more complex systems.
So let’s start with the authentication process for our API. I’ll first list here the authentication steps and we’ll go into further details after. Basically the flow to access our API will be the following:
- Client requests a JWT to authenticate it’s requests:
POST /token -d username=user -d password=pass
- API Server verifies the username/password combination and generates a JWT to be returned. If user/password combination
is not valid a
401 Unauthorizederror will be returned.
- Client stores somewhere the JWT (for example in the
localStorageif it’s a web browser).
- Client sends requests to access resources including the JWT in the
Authorizationheader of the request.
- API verifies that the JWT is valid and returns the resource data or
401 Unauthorizedif it’s not valid.
So it’s time to clear the doubts in that JWT thing I mentioned a few times already in this post.
JWT (JSON Web Token)
As stated in the JWT.io website:
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
Basically a JWT is a JSON object encoded in a base 64 String which contains information about an entity (user or API client). The good
thing is that this String is compact and it can be sent as a request
POST parameter or even in a request header
(as we’ll use it).
At this point you might be asking yourself how is it that we should trust an encoded string that the client is sending. What if the client makes up the encoded string with fake data? The secret is that the JWT that the API server returns to the client is digitally signed with a secret key known by the server only and using the HMAC algorithm. This way, the server will always check if the signature is valid before analysing the JWT contents. So unless you give your secret key to people, nobody without username/password authentication would be able to access your API.
The JWT encoded String is divided into 3 sections: Header, Payload and Signature. You can find more details about JWT sections in the JWT.io website.
The ST in REST
So why all this JWT thing instead of doing some kind of log in endpoint and keep a session active for some predefined time? That’s when the ST part of REST comes into play. The meaning of REST is “Representational State Transfer”. State Transfer means that in every HTTP request we transfer the state, we don’t need to store the state in any server. So the session status is always maintained by the clients, and clients are the ones sending session information to the server with every request.
This has many advantages, but is specially important to scale our API. The fact of having no session data in our API servers allows us to have multiple instances to serve as many clients as we want, and any instance can serve any client at any time. There’s no session data on the server, which means that different servers can take care of consecutive requests from the same client. Because the client sends the session data in the request (the JWT), each server can verify if it’s a valid client or not with every request. A very good explanation can be found on this stack overflow answer by Jarrod Roberson.
Ok, now that we understand all this JWT thing let’s see how can we implement it in our API to make it more secure.
We’ll need to install the
jsonwebtoken module in order to generate JWT
for valid users. We also need to install the
express-jwt module which provides
a useful middleware that will check if the JWT sent with the requests is valid or not.
The Auth Controller
Let’s first create the functions that will handle the initial authentication of a user. This is steps 1 and 2 of the
authentication flow. Go to the
server/controllers directory and create an
We’ll organize our authentication flow with three steps, which will be implemented by a controller function each:
authenticate: Will check for the username/password correctness
generateToken: Will generate the JWT
respondJWT: Will send the JWT back to the client
For the step number 1, add the following code to the
server/controllers/auth.js file you just created:
Here we simply check first that a user with the provided
req.body.username exists. If it exists, we then check if the
req.body.password is the correct one by using the
comparePassword instance method we created in the previous
post “The Database: Setup”.
If password is correct we then call the next middleware for the route.
Now let’s add some code to generate a JWT for the authenticated user. In order to create a JWT, we’ll need to define a
secret key which we’ll use to sign the JWT and recognize later if the JWT sent by the client wasn’t manipulated. So
we need to create a new configuration property in our
config/env/development.js file named
jwtSecret. And we will
also add another configuration property for the JWT duration:
After this we’re ready to add some code to generate a JWT to our auth controller:
Note the two added imports on the top. Within this function we define our JWT payload which will include only the
_id property, which is enough for our server to identify a user. Then we set the expiration date for the token
and we finally sign it using the secret defined in our configuration file. After signing we pass control to the next
middleware which will be the one sending the response back. So let’s add the code for the last authentication
Note that I’ve added the export statement as well at the end of the controller.
All set in the controller side, let’s configure the authentication route.
The Auth Route
Create a new
auth.js file within the
server/routes directory and put the following contents on it:
Now let’s hook the route definition under the
/auth path on our api by adding to the
server/routes/index.js file this
All set! We’re ready to check if our API can generate a JWT and return it back to the client. Go to your console and try it:
The answer should look like this:
And if you send a wrong password or username you’ll get this:
You can even go to the JWT.io Debugger and paste the JWT that your API is returning to
see if it’s correct. And you can also try putting the
jwtSecret from the config file in the debugger to check if the
signature is valid.
Validating Incoming JWTs
So far we provided our clients with a JWT that they can use in subsequent requests, but we didn’t add any code to
validate if the JWT that the client is sending is valid or not. Here is where we’ll use the
we installed a while ago.
Go to the
config directory and create a
jwt.js file there with the following contents:
We’re exporting the
jwt function which is nothing else than an express middleware that checks for the incoming requests
Authorization header. By default it will check for values equal to
JWT [JWT_STRING], so a valid header would be for
Now let’s use this middleware in our routes configuration to add the authentication layer. I’ll use the
as an example, you can later add authentication to any endpoint you want to restrict to registered clients.
That’s it! By simply adding the authentication middleware at the beginning of the route middleware list you’re done. Now try to access the users listing endpoint without sending an Authorization header and you’ll get a response like this one:
Good that we have protected our endpoint, but that response doesn’t look very nice right? Let’s make things right. Go
config/express.js file and add the following error handling middleware after the
This will take care of all errors carried by the calls to
next(err) in our controller functions. Now try again to access
the user listing endpoint without a JWT, the response will look like this:
Better right? So that’s it, you can now add the
auth middleware to any route you want to protect it from unauthorized
Coming up next…
We have our endpoints secured with a session-less approach with the help of JWT. We’re almost there, the last two things we have to do are adding validation of data to our endpoints and add some unit testing with mocha. To continue with the validation head over to the next post!
If you enjoyed reading, retweet or like this tweet!
Adding security to our RESTful API through the use of JSON Web Tokens https://t.co/65STooJf9t— Mauricio Payetta (@mpayetta) 2 de agosto de 2016
Building a Node.js REST API 6: Authentication by Mauricio Payetta is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License .