JWT Tokens in Express and NodeJS



The JSON Web Token (JWT) is the easiest standard for protecting APIs and passing in claims data. A JSON Web token allows the server to verify the authenticity of the user and provide them access to protected API routes and data.  A simple JWT flow goes as follows:

  1. The user sends login credentials to the server
  2. The server verifies user against the database then returns a JWT token if valid
  3. The user sends that token in the header with every request to API.
  4. If JWT token is valid (untampered) and not expired, server processes request. Otherwise, the user must sign in to obtain new JWT.

A JWT is just an encoded string that could look something like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o

Remember, this string **is encoded and not encrypted! **JSON Web Tokens are not meant to be a means for hiding data. The server simplify verifies the decoded string with the secret (stored on the server) to see if it has been tampered with.

Let’s take a look at how to implement JWT Tokens in Express and NodeJS.

Basic Express Application

Here is a basic express application with two routes: Login, Home. We are using a hard-coded user for this demo instead of an actual database. The server will check to see if the user’s email and password match the hard-coded value. If it does, we return to them “a token”. If not, we send a 400 response.

<code class="lang-javascript">

const express = require('express')
var bodyParser = require('body-parser')
const app = express()

const user = { email: '[email protected]', password: 1234 }


app.use(bodyParser.urlencoded({ extended: false }));


app.get('/home', (req, res) => {
    res.send('Congratulations, you made it to home');
})

app.post('/login', (req, res) => {
    if (req.body.email == user.email && req.body.password == user.password) {
           res.send('a token');
        }else{
            res.sendStatus(400);
        }
})

app.listen(8090, () => console.log('Example app listening on port 8090!'))

</code>

So this is fine, but now we want to make the home route protected so that only valid users who are logged in are able to access it. This is where the JWT will come in handy. Instead of returning ‘a token’ in the login response, we are going to return a valid JWT.

Create Token

Let’s create a function called create token. It will create a JWT token that expires 30 seconds in the future and contains the user’s email as the payload. For this, we are going to use the jsonwebtoken library.

function createToken(){
    // sign with default (HMAC SHA256)
    let expirationDate =  Math.floor(Date.now() / 1000) + 30 //30 seconds from now
    var token = jwt.sign({ userID: user.email, exp: expirationDate }, secret);
    return token;
}

Also, let’s define the secret to use. For simplicity, let’s just call it secret. But please don’t do that in production:

const secret = 'secret';

Modify the login response to return the token instead of ‘a token’.

if (req.body.email == user.email && req.body.password == user.password) {
            res.send(createToken())
        }else{
            res.sendStatus(400);
        }

Validating Token

So now the user will receive a token when he logins. The next step is for our server to verify the token for the protected route. For this, we are going to use the jwt middlware for express.

Now let’s modify the home route to process the token. By default, the middleware assumes that the token will be located in a header called Authorization. If you are testing this with postman, make sure that you have a header called Authorization with its value as _Bearer Your_ACTUAL_Token. _As for the secret, pass it the name of your variable that stores the secret.

app.get('/home',jwtVerifier({secret: secret}), (req, res) => {
    res.send('Congratulations, you made it to home');
})

Now when the user accesses the home route it will check to see if the token is valid and not expired. If that is the case, the request is processed. Otherwise, we throw him an error. Let’s define the error below:

app.use((err, req, res, next) => {
    if (err.name === 'UnauthorizedError') {
        res.status(500).send(err.message);
    }
});

There you go. Test the application and give it a try. If a valid user logs in they will get a JWT that’s valid for 30 seconds. They can then access the home route along as they have that token in their request header and it’s not expired or tampered with. Otherwise, we through them an error and they will need to get a new token.

You can view the full code on GitHub.