{ Authentication with JSON APIs. }


By the end of this chapter, you should be able to:

  • Describe how to secure an API
  • Understand what a JWT is and how to create one
  • Authenticate an API using JSON Web Tokens

Authenticating an API

So how do we secure our API? We can do what we have been doing before and store information in the session and in cookies, but this can become problematic. This is especially true when you're working with lots of different servers (lots of small applications written in different languages) or when you're building mobile applications, which have severe limitations with cookies.

Instead of using cookies/sessions to authenticate users, we will be using tokens. This process involves creating an encrypted token on the server and sending it to the client where it will either be stored in a cookie or in localStorage (more commonly done with localStorage), and on every future request, the token will be placed in the header and will be decrypted on the server.

The server will store a secret key used to encrypt and decrypt the token so that there can not be tampering with the token in the client.

You can read more about tokens versus cookies here.

The type of token that we will be using is a JSON Web Token, or JWT (pronounced "jot").

Using JWTs

Before we continue, read through this introduction to JWTs so you can understand a bit more about what they are and how they work. JWTs are a means of securing information between two parties and consist of three parts:

  • Header - metadata about the token (the type of algorithm used to sign and the type of token)
  • Payload - data to be stored in the token (an object with the data we want to store like a user id)
  • Signature - the result of the algorithm specified in the header (we will be using HMAC-SHA256) with an encoded header, encoded payload, and a secret passed to it.

We can use passport-jwt for this, but let's abstract a little bit less and roll our own authentication with JSON web tokens!

Example App

The module we will be using to create secure tokens is jsonwebtoken.

We will start with a simple application here:

mkdir learn_jwt && cd learn_jwt
touch app.js
npm init -y
npm install --save express body-parser mongoose jsonwebtoken


// npm packages
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
const express = require('express');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');

// app imports
const { User } = require('./models');

// globals
const app = express();
// you MUST put this in a .env file

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

mongoose.Promise = Promise;
mongoose.set('debug', true);
  .then(() => {
    console.log('Connected to Database.');
  .catch(err => {
    console.log('Error Connecting to Database');

app.post('/signup', (req, res) => {
  User.create(req.body).then(user => res.status(201).json(user));

app.post('/authenticate', (req, res, next) => {
  // find a user by their name
  return User.findOne({ name: req.body.name }).then(
    user => {
      // if there is no user
      console.log('USER', user);
      if (!user) {
        return res.status(401).json({ message: 'Invalid Credentials' });
      return user.comparePassword(req.body.password, (err, isMatch) => {
        if (isMatch) {
          const token = jwt.sign({ name: user.name }, SECRET, {
            expiresIn: 60 * 60 // expire in one hour
          return res.json({
            message: 'Authenticated!',
        } else {
          return res.status(401).json({ message: 'Invalid Credentials' });
    err => next(err)

app.use((req, res, next) => {
  // Is there a token in the query string  /users?token=1a2b3c4d5e6f7
  const queryToken = req.query.token;

  // Is there a token in the Authorization header?
  //   req.headers looks like this --> { Authorization: Bearer 1a2b3c4d5e6f7 }
  const headerToken =
    req.headers.Authorization && req.headers.Authorization.split(' ')[1];

  const token = queryToken || headerToken;

  if (token) {
    jwt.verify(token, SECRET, (err, decoded) => {
      if (err) {
        return res.json({ message: 'Invalid Token' });
      } else {
        req.decoded = decoded;
        return next();
  } else {
    return res.status(401).json({ message: 'No token provided.' });

// catch 404 and forward to error handler
app.use((req, res, next) => {
  const err = new Error('Not Found');
  err.status = 404;
  return next(err);

// error handler
app.use((err, req, res, next) =>
  res.status(err.status || 500).json({
    message: err.message || 'Internal Server Error'

app.listen(3000, () => {
  console.log('Server is listening on port 3000');


const userSchema = new mongoose.Schema({
  name: String,
  password: String

userSchema.pre('save', function(next) {
  const user = this;

  if (!user.isModified('password')) {
    return next();

  bcrypt.hash(user.password, 10).then(
    hashedPassword => {
      user.password = hashedPassword;
      return next();
    err => next(err)

userSchema.methods.comparePassword = function(candidatePassword, next) {
  bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
    if (err) {
      return next(err);
    return next(null, isMatch);

// set up a mongoose model
const User = mongoose.model('User', userSchema);

Enabling CORS

When setting up a Node.js API on its own (without any kind of front-end), we will be accessing the API most likely from a different domain. Since the same origin policy enforces that we can not run JavaScript on another domain, we need to enable our API to bypass that security policy through allowing certain origins (domains).

Cross Origin Resource Sharing (or CORS) is one way of doing this. By adding specific headers on the server, we can enable browsers to execute JavaScript on the domain that the API is hosted on. To enable CORS, we can either manually add the headers ourselves, or use the helpful CORS module.

Sample application

You can see a sample application with JSON API Authentication here.

When you're ready, move on to Testing JSON APIs


Creative Commons License