@futurestudio/hapi-jwt
v2.1.1
Published
hapi plugin to sign, decode, and invalidate/blacklist JWTs
Downloads
9
Readme
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 inkeys
keys
: (object) describing a key pair when using asymmetric algorithmspublic
: (string) the path to the public key. The public key must be in PEM formatprivate
: (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 algorithmttl
: (number, default: 15) the JWT lifetime in minutesblacklist
: (object) configurating the blacklistenabled
: (boolean, default: false) enables the blacklistcache
: (object) configures a hapi cache instance for the JWT blacklist. These options are used to create a cache via server.cachename
: (string) identifies both, the blacklisting cache name and segmentprovider
: (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 JWTawait 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 blacklistawait 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 identifieriat
: issued at date in secondsnbf
: validity start date in secondsexp
: expiration date in seconds, based on the TTLiss
: retrieves the token issuer from the request domainsub
: if the givenuser
object contains anid
field, it will be used for thesub
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 objectget(key)
: returns the value identified bykey
has(key)
: returns a boolean,true
if the payload contains the claim identified bykey
, otherwisefalse
missing(key)
: returns a boolean,true
if the payload does not contain the claim identified by key, otherwisefalse
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
- hapi tutorial series with 100+ tutorials
Contributing
- 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 🚀
License
MIT © Future Studio
futurestud.io · GitHub @futurestudio · Twitter @futurestud_io