 
  Seamless JWT signing, decoding, and blacklisting in your hapi app.
Installation · Plugin Options · Usage
Follow @marcuspoehls for updates!
The Future Studio University supports development of this hapi plugin 🚀
Join the Future Studio University and Skyrocket in Node.js
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()
This plugin requires Node.js v12 or newer.
| Major Release | hapi.js version | Node.js version | 
|---|---|---|
| v2 | >=18 hapi | >=12 | 
| v1 | >=18 hapi | >=8 | 
Install hapi-jwt as a dependency to your project:
npm i @futurestudio/hapi-jwtRegister 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 :)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
 
 
hapi-jwt decorates hapi’s request object with a JWT instance: request.jwt.
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
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- userobject contains an- idfield, it will be used for the- subclaim
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
}
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
    }
  }
})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,- trueif the payload contains the claim identified by- key, otherwise- false
- missing(key): returns a boolean,- trueif the payload does not contain the claim identified by key, otherwise- false
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.
- hapi tutorial series with 100+ tutorials
- Create a fork
- Create your feature branch: git checkout -b my-feature
- Commit your changes: git commit -am 'Add some feature'
- Push to the branch: git push origin my-new-feature
- Submit a pull request 🚀
MIT © Future Studio
futurestud.io · GitHub @futurestudio · Twitter @futurestud_io