Authenticate a Node.js API with JSON Web Tokens

Introduction

Authentication is one of the big parts of every application. Security is always something that is changing and evolving. In the past, we have gone over Node authentication using the great Passport npm package.

Those articles used the session based authentication however, which has problems when we talk about scaling web services and creating an API that can be consumed across many devices and services.

The other file we'll need to create is our config.js file. This is where we can store different variables and configuration for our application.

Config File (config.js)

For this file, you will need to create MongoDB database. You can either create one locally or easily use one online at modulus.io for free. Either way, you will be able to get a URI string to use as your database configuration.

database: the URI with username and password to your MongoDB installation

With all that out of the way, we can get to the big parts of our tutorial. We still haven't defined our main file (server.js), so let's get to that.

The Actual Node Application (server.js)

In this file, we will:

Grab All the Packages This will include the packages we installed earlier (express, body-parser, morgan, mongoose, and jsonwebtoken) and also we'll be grabbing the model and config that we created.

Configure Our Application We will set our important variables, configure our packages, and connect to our database here.

Create Basic Routes These are the unprotected routes like the home page (http://localhost:8080). We'll also create a /setup route here so that we can create a sample user in our new database.

Create API Routes This includes the following routes:

POST http://localhost:8080/api/authenticate Check name and password against the database and provide a token if authentication successful. This route will not require a token because this is where we get the token.

GET http://localhost:8080/api Show a random message. This route is protected and will require a token.

GET http://localhost:8080/api/users List all users. This route is protected and will require a token.

It's important to note that we would **never** save a password to the database plain text like this. You would protect your passwords by hashing it.

Go ahead and visit your application at http://localhost:8080/setup. You should see the message 'User saved successfully' logged to your console and the JSON object with { success: true } in your browser.

We'll now create a route to get the users in our database and return them as JSON.

Showing Our User

Now let's create our API routes and create one to return all our users in JSON format. We'll use an instance of the Express router for this. We'll place a few placeholders so we can see where things will go. Here is the code for that:

We now have two routes that we can use. We can see these in our browser again, but at this point, let's switch over to POSTman.

For the URL, use: http://localhost:8080/api/ and we will be able to see the message.

Then we can go to: http://localhost:8080/api/users and see the list of users.

This is great that we have been able to create a user and show them. We probably don't want any random person to see our list of users however.

Next, let's make sure that we can authenticate a user and then protect those routes using Express route middleware and requiring a token.

Authenticating and Creating a Token

Let's make our POST http://localhost:8080/api/authenticate route where we will accept a name and a password (probably from a form). If the name and password validate, then we will create a token and pass that back.

Once the user has that token, they will store it client side and pass it with every request for information after that and we will validate the token on every request using route middleware.

With this code, we can check our user and password and pass back a token in a JSON response. We are using mongoose to find the user and jsonwebtoken to create the token.

Let's test this out using POSTman. Change your HTTP request to POST and add the name and password parameters to x-www-form-urlencoded. This is how we simulate information coming through a form POST.

Remember the user we created earlier had a name of Nick Cerminara and a password of password. (super safe, I know)

Here's the route using the wrong name:

Using the right name and wrong password:

When everything goes well:

You can see that in our response, we are given our token! Now let's copy and paste that token somewhere safe until we are able to use it after we create our route middleware next.

Route Middleware to Protect API Routes

At this point, we have 3 routes defined on our API routes (/api/authenticate, /api, and /api/users). Let's create route middleware to protect the last 2 routes. We won't want to protect the /api/authenticate route so what we'll do is place our middleware beneath that route. Order is important here.

We are using the jsonwebtoken package again, but this time we are going to verify the token that was passed in. It is important that our secret used here matches the secret that was used to create the token. We are also making sure to send the right HTTP response code as 403 forbidden and our user was not authenticated to view any data.

If everything looks good the token was able to be verified, we'll take the information that came out of the token and pass it to the other routes in the req object.

Testing Our Middleware

We have built our middleware that our Node application will run through before it gets to the routes that we want authenticated.

Let's go into POSTman again and try to access both routes without passing a token.

This is our route without the token just accessing the base api route of http://localhost:8080/api:

Now let's pass in the token that was created before in our HTTP header as x-access-token accessing the users list at http://localhost:8080/api/users:

We can also pass it in as a URL parameter by going to: http://localhost:8080/api/users?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NDY1MDViMDFmYTAzYmUwMTUxMDYwOWIiLCJuYW1lIjoiTmljayBDZXJtaW5hcmEiLCJwYXNzd29yZCI6InBhc3N3b3JkIiwiYWRtaW4iOnRydWUsIl9fdiI6MH0.ah-NFQ1967WVeN6lYNAahT7hZtshG6kw6AW3ncuJOYw

Conclusion

This is a good look at how we can protect routes and our Node API using JSON Web Tokens. This can be expanded into a much larger scoped project like providing permission specific tokens and creating a more robust and feature filled API.

Hopefully this look has given you a good understanding of how the routes are used (especially middleware), tokens are created, and requests to the API all come together.