/rex-jwt-middleware

Easily implementable security package for REST Api for an Express server with MongoDB. Security strategy is build around JWTs.

Primary LanguageJavaScript

rex-jwt-middleware

rex-jwt-middleware is a package made with the intention to take care of a lot of the boilerplate code for basic user authentication with JWT's, using bcryptjs, jsonwebtoken, cookie, and mongoose. Best used with package rex-jwt-client.

Contents

Installation

npm i rex-jwt-middleware
yarn add rex-jwt-middleware

Setup

(I'll describe how this all works in the next sections.)

Add the following next to all other express middleware:

const { TokenProcessor } = require('rex-jwt-middleware')

app.use(new TokenProcessor({
  refreshToken: {
    secret: process.env.REFRESH_TOKEN_SECRET,
    exp: 20 * 60, // Number of seconds from epoch
    route: '/api/refresh',
    cookieName: 'rex',
  },
  accessToken: {
    secret: process.env.ACCESS_TOKEN_SECRET,
    exp: 10,
  },
}))

Parameters:

refreshToken

param description
secret Random string used to encrypt our refresh token.
exp Number of seconds this token is meant to last.
route Name of route for the cookie containing the refresh token. This route must match the name of the route used with the user.refresh middleware function below.
cookieName Name of the cookie that will contain the refresh token

accessToken

param description
secret Random string used to encrypt our access token.
exp Number of seconds this token is meant to last.

Setting up our User model:

Before creating our routes and using our middleware, we need to initialize the User model for our RexUser by providing a schema. Adding fields to the schema is done in the same way one can add fields to a mongoose schema.

const { RexUser } = require('rex-jwt-middleware')

const user = RexUser({
  email: {
    type: String,
    min: 6,
    required: true,
  },
  password: {
    type: String,
    min: 50,
    required: true,
  },
  firstName: {
    type: String,
    required: true
  },
  // etc.
})

Use

Adding authentication/registration routes:

These routes can be called anything. This is just an example:

app.post('/api/register', user.register)
app.post('/api/login', user.login)
app.post('/api/logout', user.logout)

Adding a route to refresh an expired access token:

We need to add one more route for the refresh token, so that we can send back an access token when the user needs to access protected routes. This route must be the same as the route field in the refreshToken field in the TokenProcessor object above. Meaning, this route and that can be named whatever you want them to be named, but they have to match.

app.post('/api/refresh', user.refresh)

Setting up a protected route:

Protected routes can only be accessed if the user sends us a valid access token.

app.get('/secret', user.protect, (req, res) => {
  res.send("here is some secret content")
})

Description of the process:

This package uses two JWT's to carry out authentication, an access token and a refresh token. When a user logs into the site, they receive these two tokens. The access token can be stored either in memory or localStorage, and the refresh token gets stored in an HTTP only cookie.

The access token is what allows a user to access protected routes. Once the access token expires, as long as the refresh token hasn't expired, the refresh route can be used to get a new access token before accessing a protected route.