{"id":20426508,"url":"https://github.com/futurestudio/hapi-jwt","last_synced_at":"2025-04-12T19:08:16.454Z","repository":{"id":43341271,"uuid":"220975381","full_name":"futurestudio/hapi-jwt","owner":"futurestudio","description":"hapi plugin to sign, verify, and invalidate/reject JWTs","archived":false,"fork":false,"pushed_at":"2022-03-07T08:44:39.000Z","size":280,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T19:08:04.721Z","etag":null,"topics":["future-studio-university","hapi","hapi-plugin","hapijs","jwt","jwt-decode","jwt-payload","jwt-signing","node","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/futurestudio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-11T12:21:11.000Z","updated_at":"2024-10-23T04:17:03.000Z","dependencies_parsed_at":"2022-09-21T01:11:35.510Z","dependency_job_id":null,"html_url":"https://github.com/futurestudio/hapi-jwt","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurestudio%2Fhapi-jwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurestudio%2Fhapi-jwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurestudio%2Fhapi-jwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurestudio%2Fhapi-jwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/futurestudio","download_url":"https://codeload.github.com/futurestudio/hapi-jwt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248618276,"owners_count":21134200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["future-studio-university","hapi","hapi-plugin","hapijs","jwt","jwt-decode","jwt-payload","jwt-signing","node","nodejs"],"created_at":"2024-11-15T07:16:46.787Z","updated_at":"2025-04-12T19:08:16.433Z","avatar_url":"https://github.com/futurestudio.png","language":"JavaScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/futurestudio/hapi-jwt/blob/master/media/hapi-jwt.png?raw=true\" alt=\"hapi-jwt logo\" width=\"471\" style=\"max-width:100%;\"\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n\n  \u003cp\u003e\n    Seamless JWT signing, decoding, and blacklisting in your hapi app.\n  \u003c/p\u003e\n\n  \u003cbr/\u003e\n  \u003cp\u003e\n    \u003ca href=\"#installation\"\u003e\u003cstrong\u003eInstallation\u003c/strong\u003e\u003c/a\u003e ·\n    \u003ca href=\"#plugin-options\"\u003e\u003cstrong\u003ePlugin Options\u003c/strong\u003e\u003c/a\u003e ·\n    \u003ca href=\"#usage\"\u003e\u003cstrong\u003eUsage\u003c/strong\u003e\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://travis-ci.com/futurestudio/hapi-jwt\"\u003e\u003cimg src=\"https://travis-ci.com/futurestudio/hapi-jwt.svg?branch=master\" alt=\"Build Status\" data-canonical-src=\"https://travis-ci.com/futurestudio/hapi-jwt.svg?branch=master\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/@futurestudio/hapi-jwt\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/@futurestudio/hapi-jwt.svg\" alt=\"hapi-jwt Version\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003cem\u003eFollow \u003ca href=\"http://twitter.com/marcuspoehls\"\u003e@marcuspoehls\u003c/a\u003e for updates!\u003c/em\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n------\n\n\u003cp align=\"center\"\u003e\u003csup\u003eThe \u003ca href=\"https://futurestud.io\"\u003eFuture Studio University\u003c/a\u003e supports development of this hapi plugin 🚀\u003c/sup\u003e\n\u003cbr\u003e\u003cb\u003e\nJoin the \u003ca href=\"https://futurestud.io/university\"\u003eFuture Studio University and Skyrocket in Node.js\u003c/a\u003e\u003c/b\u003e\n\u003c/p\u003e\n\n------\n\n\n## Introduction\n`hapi-jwt` is a hapi plugin to create (sign) and access (decode) JSON web tokens (JWT).\n\nCreate a token via `request.jwt.for(user)` and retrieve the payload of an existing token via `request.jwt.payload()`\n\n\n## Requirements\nThis plugin requires **Node.js v12 or newer**.\n\n\n### Compatibility\n| Major Release | [hapi.js](https://github.com/hapijs/hapi) version | Node.js version |\n| --- | --- | --- |\n| `v2` | `\u003e=18 hapi` | `\u003e=12` |\n| `v1` | `\u003e=18 hapi` | `\u003e=8` |\n\n\n## Installation\nInstall `hapi-jwt` as a dependency to your project:\n\n```bash\nnpm i @futurestudio/hapi-jwt\n```\n\n\n### Register the Plugin\nRegister `hapi-jwt` as a plugin to your hapi server.\n\n```js\nawait server.register({\n  plugin: require('@futurestudio/hapi-jwt'),\n  options: {\n    secret: 'your-secret' // this is the minimum required configuration to sign/decode JWTs\n  }\n})\n\n// went smooth like hot chocolate :)\n```\n\n\n### Plugin Options\nThis plugin ships with a comprehensive [default configuration](https://github.com/futurestudio/hapi-jwt/blob/master/config/default.js). Please have a look at all available keys and related comments.\n\nThe following list outlines all options:\n\n- **`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`\n- **`keys`:** (object) describing a key pair when using asymmetric algorithms\n  - **`public`:** (string) the path to the public key. The public key must be in PEM format\n  - **`private`:** (string) the path to the private key. The private key can be in PEM format, OpenSSH format works as well.\n- **`algorithm`:** (string, default: HS256) the JWT signing algorithm\n- **`ttl`:** (number, default: 15) the JWT lifetime in minutes\n- **`blacklist`:** (object) configurating the blacklist\n  - **`enabled`:** (boolean, default: false) enables the blacklist\n  - **`cache`:** (object) configures a hapi cache instance for the JWT blacklist. These options are used to create a cache via [server.cache](https://hapi.dev/api/?v=18.4.0#-servercacheoptions)\n     - **`name`:** (string) identifies both, the blacklisting cache name and segment\n     - **`provider`:** (string) defines the catbox caching client, like `@hapi/catbox-redis`\n\n\n## Usage\n`hapi-jwt` decorates hapi’s request object with a JWT instance: `request.jwt`.\n\n\n### Request Decorations\nThis decoration provides a convenient interface to interact with JWTs:\n\n  - `await request.jwt.for(user)`: creates a signed JWT\n  - `await request.jwt.payload()`: returns the decoded JWT payload. This expects a valid JWT as a bearer token in the authorization header.\n  - `await request.jwt.invalidate()`: decodes the JWT on the request (see payload method) and adds it to to the blacklist\n  - `await request.jwt.invalidate('forever')`: blacklists a JWT indefinitely\n\n\n### Create a JWT\nCreating a (signed) JWT is as simple as `await request.jwt.for({ id: 1, name: 'Marcus' })`:\n\nWhen creating the JWT, `hapi-jwt` creates a handful of claims besides your provided data. It generates the following claims:\n\n- `jti`: a token identifier\n- `iat`: issued at date in seconds\n- `nbf`: validity start date in seconds\n- `exp`: expiration date in seconds, based on the TTL\n- `iss`: retrieves the token issuer from the request domain\n- `sub`: if the given `user` object contains an `id` field, it will be used for the `sub` claim\n\n\n```js\nserver.route({\n  method: 'POST',\n  path: '/login',\n  options: {\n    auth: 'basic', // assume the login route requires basic authentication\n    handler: async request =\u003e {\n      const token = await request.jwt.for(request.auth.credentials)\n\n      return token\n    }\n  }\n})\n```\n\nYou can debug a created JWT on [jwt.io](https://jwt.io/) and have a look at the token headers and payload.\n\nA sample token payload looks like this:\n\n```\n{\n  jti: 'babf5099a4561173c91f2cdc6c61c1aa',\n  iss: 'http://localhost',\n  iat: 1574094111,\n  nbf: 1574094111,\n  exp: 1574095011,\n  sub: 1\n}\n```\n\n\n### Decode a JWT and access the payload\nYou 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 \u003cyour-jwt\u003e`.\n\nCalling `request.jwt.payload()` returns a `Payload` instance containing the JWT claims set:\n\n```js\nserver.route({\n  method: 'GET',\n  path: '/me',\n  options: {\n    auth: 'jwt',\n    handler: async request =\u003e {\n      const payload = await request.jwt.payload()\n\n      const user = payload.has('sub')\n        ? await User.findbyId(payload.get('sub'))\n        : await User.findOne({ email: payload.get('email') })\n\n      return user\n    }\n  }\n})\n```\n\n\n#### Payload\nA payload instance returned from `await request.jwt.payload()` has the following methods:\n\n- **`toObject`:** returns a plain JavaScript object\n- **`get(key)`:** returns the value identified by `key`\n- **`has(key)`:** returns a boolean, `true` if the payload contains the claim identified by `key`, otherwise `false`\n- **`missing(key)`:** returns a boolean, `true` if the payload **does not** contain the claim identified by key, otherwise `false`\n\n\n## JWT Blacklist\nActivating the JWT blacklist requires a cache. `hapi-jwt` uses hapi’s [`server.cache`](https://hapi.dev/api/?v=18.4.0#-servercacheoptions) method to provision a blacklist storage.\n\nWhen using the blacklist, please ensure a persistent caching store, like Redis via [@hapi/catbox-redis](https://github.com/hapijs/catbox-redis) or Memcached via [@hapi/catbox-memcached](https://github.com/hapijs/catbox-memcached). Using hapi’s default internal caching instance stores the blacklist in-memory and will be gone when restarting the server.\n\n\n## Links \u0026 Resources\n\n- [hapi tutorial series](https://futurestud.io/tutorials/hapi-get-your-server-up-and-running) with 100+ tutorials\n\n\n## Contributing\n\n1.  Create a fork\n2.  Create your feature branch: `git checkout -b my-feature`\n3.  Commit your changes: `git commit -am 'Add some feature'`\n4.  Push to the branch: `git push origin my-new-feature`\n5.  Submit a pull request 🚀\n\n\n## License\n\nMIT © [Future Studio](https://futurestud.io)\n\n---\n\n\u003e [futurestud.io](https://futurestud.io) \u0026nbsp;\u0026middot;\u0026nbsp;\n\u003e GitHub [@futurestudio](https://github.com/futurestudio/) \u0026nbsp;\u0026middot;\u0026nbsp;\n\u003e Twitter [@futurestud_io](https://twitter.com/futurestud_io)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuturestudio%2Fhapi-jwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffuturestudio%2Fhapi-jwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuturestudio%2Fhapi-jwt/lists"}