@futurestudio/hapi-jwt
TypeScript icon, indicating that this package has built-in type declarations

2.1.1 • Public • Published
hapi-jwt logo

Seamless JWT signing, decoding, and blacklisting in your hapi app.


Installation · Plugin Options · Usage



Build Status hapi-jwt Version

Follow @marcuspoehls for updates!


The Future Studio University supports development of this hapi plugin 🚀
Join the Future Studio University and Skyrocket in Node.js


Introduction

hapi-jwt is a hapi plugin to create (sign) and access (decode) JSON web tokens (JWT).

Create a token via request.jwt.for(user) and retrieve the payload of an existing token via request.jwt.payload()

Requirements

This plugin requires Node.js v12 or newer.

Compatibility

Major Release hapi.js version Node.js version
v2 >=18 hapi >=12
v1 >=18 hapi >=8

Installation

Install hapi-jwt as a dependency to your project:

npm i @futurestudio/hapi-jwt

Register the Plugin

Register hapi-jwt as a plugin to your hapi server.

await server.register({
  plugin: require('@futurestudio/hapi-jwt'),
  options: {
    secret: 'your-secret' // this is the minimum required configuration to sign/decode JWTs
  }
})

// went smooth like hot chocolate :)

Plugin Options

This plugin ships with a comprehensive default configuration. Please have a look at all available keys and related comments.

The following list outlines all options:

  • secret: (string) the secret key used to sign and decode a JWT (with a symmetric algorithm). The secret is required if you don’t use a keypair provided in keys
  • keys: (object) describing a key pair when using asymmetric algorithms
    • public: (string) the path to the public key. The public key must be in PEM format
    • private: (string) the path to the private key. The private key can be in PEM format, OpenSSH format works as well.
  • algorithm: (string, default: HS256) the JWT signing algorithm
  • ttl: (number, default: 15) the JWT lifetime in minutes
  • blacklist: (object) configurating the blacklist
    • enabled: (boolean, default: false) enables the blacklist
    • cache: (object) configures a hapi cache instance for the JWT blacklist. These options are used to create a cache via server.cache
      • name: (string) identifies both, the blacklisting cache name and segment
      • provider: (string) defines the catbox caching client, like @hapi/catbox-redis

Usage

hapi-jwt decorates hapi’s request object with a JWT instance: request.jwt.

Request Decorations

This decoration provides a convenient interface to interact with JWTs:

  • await request.jwt.for(user): creates a signed JWT
  • await request.jwt.payload(): returns the decoded JWT payload. This expects a valid JWT as a bearer token in the authorization header.
  • await request.jwt.invalidate(): decodes the JWT on the request (see payload method) and adds it to to the blacklist
  • await request.jwt.invalidate('forever'): blacklists a JWT indefinitely

Create a JWT

Creating a (signed) JWT is as simple as await request.jwt.for({ id: 1, name: 'Marcus' }):

When creating the JWT, hapi-jwt creates a handful of claims besides your provided data. It generates the following claims:

  • jti: a token identifier
  • iat: issued at date in seconds
  • nbf: validity start date in seconds
  • exp: expiration date in seconds, based on the TTL
  • iss: retrieves the token issuer from the request domain
  • sub: if the given user object contains an id field, it will be used for the sub claim
server.route({
  method: 'POST',
  path: '/login',
  options: {
    auth: 'basic', // assume the login route requires basic authentication
    handler: async request => {
      const token = await request.jwt.for(request.auth.credentials)

      return token
    }
  }
})

You can debug a created JWT on jwt.io and have a look at the token headers and payload.

A sample token payload looks like this:

{
  jti: 'babf5099a4561173c91f2cdc6c61c1aa',
  iss: 'http://localhost',
  iat: 1574094111,
  nbf: 1574094111,
  exp: 1574095011,
  sub: 1
}

Decode a JWT and access the payload

You can access the JWT payload via await request.jwt.payload(). Accessing the payload expects a valid JWT in the authorization request header. The authorization header must be in a format like Bearer <your-jwt>.

Calling request.jwt.payload() returns a Payload instance containing the JWT claims set:

server.route({
  method: 'GET',
  path: '/me',
  options: {
    auth: 'jwt',
    handler: async request => {
      const payload = await request.jwt.payload()

      const user = payload.has('sub')
        ? await User.findbyId(payload.get('sub'))
        : await User.findOne({ email: payload.get('email') })

      return user
    }
  }
})

Payload

A payload instance returned from await request.jwt.payload() has the following methods:

  • toObject: returns a plain JavaScript object
  • get(key): returns the value identified by key
  • has(key): returns a boolean, true if the payload contains the claim identified by key, otherwise false
  • missing(key): returns a boolean, true if the payload does not contain the claim identified by key, otherwise false

JWT Blacklist

Activating the JWT blacklist requires a cache. hapi-jwt uses hapi’s server.cache method to provision a blacklist storage.

When using the blacklist, please ensure a persistent caching store, like Redis via @hapi/catbox-redis or Memcached via @hapi/catbox-memcached. Using hapi’s default internal caching instance stores the blacklist in-memory and will be gone when restarting the server.

Links & Resources

Contributing

  1. Create a fork
  2. Create your feature branch: git checkout -b my-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request 🚀

License

MIT © Future Studio


futurestud.io  ·  GitHub @futurestudio  ·  Twitter @futurestud_io

Package Sidebar

Install

npm i @futurestudio/hapi-jwt

Weekly Downloads

0

Version

2.1.1

License

MIT

Unpacked Size

104 kB

Total Files

33

Last publish

Collaborators

  • celsiusf
  • futurestud.io
  • marcuspoehls
  • peitek