Authentication with Nodejs and JWTs - a simple example
Tags: authentication
Published: 2022-01-27 20:07:16

---
title: Authentication with Nodejs and JWTs - a simple example
published: true
date: 2022-01-26 08:35:40 UTC
tags: Authentication
canonical_url: https://jsramblings.com/authentication-with-node-and-jwt-a-simple-example/
---

When it comes to JWTs, most tutorials help you build a full implementation in Node. However, they rarely stop to show just the basics - just the esssential parts that need to be there for JWT authentication to work, and nothing more.

This article aims to give a simple, straightforward overview of the steps needed to add JWT auth to a Node app.

We'll start from an unprotected API with a super secret resource and go towards securing it with JSON Web Tokens (JWTs).

### What we'll build

Our API will only contain two endpoints:

- `/login` - will return the token
- `/super-secret-resource` - the information that only logged in users should access

### Step 1: Creating a Node API with Express

Let's start from the barebones - just an API that returns a very important resource, that should only be accessed by logged in users. This endpoint should return `401 Unauthorized` if the user is not logged in. Since we don't have the `/login` endpoint yet, it will just always return 401 for now.

Create a new folder for the project, run `npm init -y` to initialize the project and run `npm install express` to install `express`.

Next, create a `server.js` file for the node app. In its simplest form, this is how the API would look:

```
// server.js
const express = require("express");
const app = express();

app.get("/super-secure-resource", (req, res) => {
  res
    .status(401)
    .json({ message: "You need to be logged in to access this resource" });
});

app.listen(3001, () => {
  console.log("API running on localhost:3001");
});

```

To start the API,  run `node server.js` in the console.

To check that the endpoint cannot be accessed, run `curl`:

```
curl -i localhost:3001/super-secure-resource

// Will output:
// 
// HTTP/1.1 401 Unauthorized
// X-Powered-By: Express
// Content-Type: application/json; charset=utf-8
// Content-Length: 62
// ETag: W/"3e-eJQzoUv1nk6AKpsmnnXBmFvKrI4"
// Date: Sat, 22 Jan 2022 09:05:53 GMT
// Connection: keep-alive
// Keep-Alive: timeout=5
// 
// {"message":"You need to be logged in to access this resource"}
```

The `-i` flag tells `curl` to also return the headers, so we can see the HTTP status code.

Notice the `401` HTTP status code - which stands for "Unauthorized" - and the message we returned from the endpoint.

### Step 2: Return a JWT token on successful login

Next, we want to allow users to login and send back a verified token if their user and password are correct.

Since setting up a full database of users and password is out of the scope of this article, we'll just hardcode an `admin/admin` user and check for that as an example.

The first step is to install the npm [jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken) module. This package will help us sign and verify JWT tokens.

```
npm install jsonwebtoken
```

Then, the endpoint will look like this:

```
const express = require("express");
const jsonwebtoken = require("jsonwebtoken");

// The secret should be an unguessable long string (you can use a password generator for this!)
const JWT_SECRET =
  "goK!pusp6ThEdURUtRenOwUhAsWUCLheBazl!uJLPlS8EbreWLdrupIwabRAsiBu";

const app = express();
app.use(express.json());

app.post("/login", (req, res) => {
  const { username, password } = req.body;
  console.log(`${username} is trying to login ..`);

  if (username === "admin" && password === "admin") {
    return res.json({
      token: jsonwebtoken.sign({ user: "admin" }, JWT_SECRET),
    });
  }

  return res
    .status(401)
    .json({ message: "The username and password your provided are invalid" });
});

```

Some things to note here:

- the `JWT_SECRET` should be an unguessable long string
- the part that actually does the signing is: `jsonwebtoken.sign({ user: "admin" }, JWT_SECRET)`

We can check a token is returned with curl:

```
curl -X POST http://localhost:3001/login --header "Content-Type: application/json" --data '{ "username": "admin", "password": "admin" }'

// {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2NDI4NDQ0NTR9.O_710gS-6t9nmqvW0_E1GlP7MdoLMFR85GXUUeskNi8"}

```

You can decode the token and see what it contains on jwt.io

![](https://jsramblings.com/content/images/2022/01/jwt-io-decoded-token.png)

Some things to note:

- The "Header" of the token contains the algorithm used - in our case, the algorithm for signing the token is HS256
- You can input your secret in the bottom right to have jwt.io verify the token signature (if the signature is verified, it means the token hasn't been tampered with)
- Besides the `{ user: admin }` which we encoded, there's also another property there - `iat`, added by the `jsonwebtoken` library; this stands for "Issued at" - i.e. when the server created the token (as Unix timestamp)

### Step 3: Send the token to the /super-secure-resource and verify it to allow access

Now let's use that token to allow the logged in user to access the restricted resource!

In order to do that, we will need to send the token to the API (as an `Authorization` header) and then verify the token on the server:

```
curl -i localhost:3001/super-secure-resource --Header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE2NDI4NDYzMzV9.gQj-qjoQwtvyU2XzER6yiT-T4DwYphjMft-kogW978c'

// Will return:
//
// HTTP/1.1 200 OK
// X-Powered-By: Express
// Content-Type: application/json; charset=utf-8
// Content-Length: 69
// ETag: W/"45-9rvFFDk8vkfruRd3Ok0vQNGIdMk"
// Date: Sat, 22 Jan 2022 10:15:03 GMT
// Connection: keep-alive
// Keep-Alive: timeout=5
//
// {"message":"Congrats! You can now accesss the super secret resource"}

```

Why this works:

- By signing the token, you ensure that the server can check that whatever token it receives, was created by itself
- If you try to tamper with the token, you'll invalidate it! The server will tell it's been tampered, so it will not authorise you!
- Try it out: take the token, change it in jwt.io and try again -> it will fail!

### Make it yours!

I specifically kept the source code for this article very barebones. Go ahead and improve it!

- Add `nodemon` to automatically reload the server when you change the API
- Add `nodeenv` and move the JWT\_SECRET to as an environment variable
- Setup an _actual_ database with users and passwords
- Add more endpoints and move the code that verifies the token in an express middleware