{"id":16824,"library":"hapi-auth-jwt2","title":"Hapi.js JWT Authentication Plugin","description":"Hapi-auth-jwt2 is a robust authentication scheme and plugin designed for Hapi.js applications, enabling secure user authentication through JSON Web Tokens (JWTs). The current stable version is 11.0.0. The project demonstrates an active release cadence, with recent version bumps addressing dependency updates, enhancing error handling, and implementing minor breaking changes to align with evolving ecosystem standards like ESLint. Its key differentiators include deep integration within the Hapi framework as a first-party plugin, a flexible `validate` function for custom user authentication logic, and support for advanced features such as 'try mode' and compatibility with multiple authentication strategies. The plugin prioritizes developer-friendliness, offering clear usage examples and comprehensive guidance on both Hapi.js and JWT fundamentals.","status":"active","version":"11.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/dwyl/hapi-auth-jwt2","tags":["javascript","Hapi.js","Authentication","Auth","JSON Web Tokens","JWT","typescript"],"install":[{"cmd":"npm install hapi-auth-jwt2","lang":"bash","label":"npm"},{"cmd":"yarn add hapi-auth-jwt2","lang":"bash","label":"yarn"},{"cmd":"pnpm add hapi-auth-jwt2","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"This is a peer dependency as `hapi-auth-jwt2` functions as a plugin for the Hapi.js framework.","package":"@hapi/hapi","optional":false},{"reason":"Required if your application logic involves signing or generating JWTs (e.g., upon user login), as the plugin primarily handles token verification. The README explicitly recommends installing this in your project.","package":"jsonwebtoken","optional":true},{"reason":"Used internally for generating standardized Hapi-compliant error responses. Custom error handling functions can be provided to override this behavior.","package":"@hapi/boom"}],"imports":[{"note":"Since v11.0.0, the package transitioned to `.cjs` file extensions for its main distribution, explicitly indicating a CommonJS module. While TypeScript environments might handle ESM `import` statements with `esModuleInterop`, the idiomatic Node.js CommonJS usage for plugin registration is `require`.","wrong":"import hapiAuthJwt2 from 'hapi-auth-jwt2';","symbol":"hapiAuthJwt2","correct":"const hapiAuthJwt2 = require('hapi-auth-jwt2');"},{"note":"When registering the plugin with a Hapi server, the CommonJS `require()` call should typically be placed directly within the `server.register()` function.","wrong":"await server.register(hapiAuthJwt2); // If 'hapiAuthJwt2' was imported via ESM 'import' without proper transpilation","symbol":"hapiAuthJwt2 plugin registration","correct":"await server.register(require('hapi-auth-jwt2'));"},{"note":"The `hapi-auth-jwt2` package ships its own TypeScript type definitions. Installing `@types/hapi-auth-jwt2` is deprecated and unnecessary.","symbol":"StrategyOptions (TypeScript)","correct":"import type { StrategyOptions } from 'hapi-auth-jwt2';"}],"quickstart":{"code":"const Hapi = require('@hapi/hapi');\nconst JWT = require('jsonwebtoken'); // Install 'jsonwebtoken' if you intend to sign tokens\n\nconst users = { // Our mock \"users database\"\n  1: {\n    id: 1,\n    name: 'Jen Jones',\n    scope: ['admin']\n  }\n};\n\n// Define your token validation function\nconst validate = async function (decoded, request, h) {\n  // In a real application, perform comprehensive checks (e.g., database lookup)\n  if (!users[decoded.id]) {\n    return { isValid: false };\n  }\n  // Return isValid: true and provide credentials for request.auth.credentials\n  return { isValid: true, credentials: users[decoded.id] };\n};\n\nconst init = async () => {\n  const server = new Hapi.server({ port: 8000, host: 'localhost' });\n\n  // Register the hapi-auth-jwt2 plugin\n  await server.register(require('hapi-auth-jwt2'));\n\n  // Configure the JWT authentication strategy\n  server.auth.strategy('jwt', 'jwt',\n    { key: process.env.JWT_SECRET ?? 'super-secret-jwt-key-replace-me',\n      validate,\n      verifyOptions: { algorithms: ['HS256'] } // Specify the algorithm if known\n    });\n\n  // Set 'jwt' as the default authentication strategy for all routes unless overridden\n  server.auth.default('jwt');\n\n  server.route([\n    {\n      method: \"GET\", path: \"/\", config: { auth: false }, // No authentication required\n      handler: function(request, h) {\n        return {text: 'Public route: Token not required. Try POST /login to get a token, then GET /restricted.'};\n      }\n    },\n    {\n      method: 'GET', path: '/restricted', config: { auth: 'jwt' }, // JWT authentication required\n      handler: function(request, h) {\n        const response = h.response({ text: `Hello, ${request.auth.credentials.name}! You used a valid Token!` });\n        response.header(\"Authorization\", request.headers.authorization);\n        return response;\n      }\n    },\n    {\n      method: 'POST', path: '/login', config: { auth: false }, // Public route to obtain a token\n      handler: function(request, h) {\n        // In a real app, securely validate username/password from request.payload\n        const user = users[1]; // Simulate successful login for user with ID 1\n        const token = JWT.sign({ id: user.id, name: user.name }, process.env.JWT_SECRET ?? 'super-secret-jwt-key-replace-me', { expiresIn: '1h', algorithm: 'HS256' });\n        return { token };\n      }\n    }\n  ]);\n\n  await server.start();\n  console.log('Server running at:', server.info.uri);\n  console.log('\\nTo test:\\n1. POST /login to get a JWT.\\n2. Copy the token.\\n3. GET /restricted with \"Authorization: Bearer <token>\" header.');\n  return server;\n};\n\ninit().catch(err => {\n  console.error('Error starting server:', err);\n  process.exit(1);\n});\n","lang":"javascript","description":"This quickstart demonstrates setting up a Hapi server with `hapi-auth-jwt2`. It includes a mock user database, a custom `validate` function to verify decoded JWTs, and registers the plugin. The example configures a 'jwt' authentication strategy, sets it as the default, and defines two routes: a public one and a restricted one. A `/login` route is also provided to issue a sample JWT, making the example fully runnable for testing authentication flow."},"warnings":[{"fix":"Ensure your Node.js environment and any custom build tools correctly resolve CommonJS modules. If you were directly importing internal plugin files, update their extensions to `.cjs`.","message":"Version 11.0.0 introduced breaking changes by renaming internal `.js` files to `.cjs` (Common JS) to conform to updated ESLint requirements. This change primarily impacts direct imports of internal plugin files, not the main package entry point.","severity":"breaking","affected_versions":">=11.0.0"},{"fix":"Update your `validate` function implementation and any consuming logic that accesses `request.auth.credentials` to expect and correctly process an object structure rather than a string. Consult the `hapi-auth-jwt2` documentation for the precise object format.","message":"Version 10.x.x changed the default structure of artifacts returned on successful authentication, transitioning from a simple String to an Object. This is a breaking change for applications that previously relied on `request.auth.credentials` being a string.","severity":"breaking","affected_versions":">=10.0.0"},{"fix":"Execute `npm install jsonwebtoken --save` in your project's root directory to add it as a direct dependency.","message":"Although `jsonwebtoken` is an internal dependency of `hapi-auth-jwt2`, it is strongly recommended to explicitly install it in your project's `package.json` if you plan to sign or generate JWTs within your application. This prevents potential module resolution issues.","severity":"gotcha","affected_versions":">=5.0.0"},{"fix":"Upgrade your Node.js runtime environment to version 18.0.0 or newer to ensure compatibility.","message":"The package now enforces a minimum Node.js engine requirement of version 18.0.0 or higher. Older Node.js versions are no longer supported and will cause installation or runtime failures.","severity":"breaking","affected_versions":">=11.0.0"},{"fix":"Upgrade `hapi-auth-jwt2` to at least version 5.1.0 to ensure proper interoperability with other Hapi authentication strategies. If upgrading is not feasible, carefully review and test the order and configuration of all authentication strategies.","message":"Prior to version 5.1.0, `hapi-auth-jwt2` had known compatibility issues when used alongside other authentication strategies, potentially leading to conflicts or unexpected behavior.","severity":"gotcha","affected_versions":"<5.1.0"},{"fix":"Upgrade `hapi-auth-jwt2` to at least version 5.0.3 to benefit from the built-in crash prevention. Additionally, ensure your custom `validate` function includes its own defensive programming and error handling for `decoded` token integrity.","message":"Earlier versions (before v5.0.3) of the plugin were vulnerable to server crashes if `JWT.decode` encountered malformed or invalid tokens, due to a lack of robust internal error handling. This was addressed by wrapping `JWT.decode` in a try/catch block.","severity":"gotcha","affected_versions":"<5.0.3"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure that `await server.register(require('hapi-auth-jwt2'));` is called and successfully awaited before any subsequent calls to `server.auth.strategy('jwt', 'jwt', { ... });` or route definitions that use the 'jwt' strategy.","cause":"This error occurs when the 'jwt' authentication strategy is referenced (e.g., in `server.auth.strategy` or `config.auth`) before the `hapi-auth-jwt2` plugin has been successfully registered with the Hapi server.","error":"Error: Unknown authentication strategy jwt"},{"fix":"For restricted routes, ensure a valid JWT is included in the request headers as `Authorization: Bearer <your_token_here>`. Confirm that `server.auth.default('jwt');` is correctly configured or that `config.auth: 'jwt'` is explicitly set for the specific route.","cause":"A Hapi route configured with `auth: 'jwt'` was accessed without a JWT being provided in the `Authorization: Bearer <token>` header, or the 'jwt' strategy was not correctly set as the default authentication strategy for the server or route.","error":"Error: Missing Authentication"},{"fix":"Verify the JWT string for correct formatting and check its expiration time. Crucially, ensure that the `key` (secret) and `verifyOptions` (e.g., `algorithms`) provided in your `server.auth.strategy` configuration precisely match the parameters used when the token was originally signed. If unsure, generate a new token.","cause":"The provided JSON Web Token is malformed, has expired, or was signed using a secret key or algorithm that does not match the configuration provided to the `hapi-auth-jwt2` strategy.","error":"Error: Invalid token"},{"fix":"Update your Hapi.js and `hapi-auth-jwt2` packages to their latest compatible versions. Reconfigure your `validate` function to be an `async` function that returns an object like `{ isValid: boolean, credentials?: object }`, instead of using a callback-based signature.","cause":"This error typically indicates an incompatibility between your Hapi.js version and `hapi-auth-jwt2`, or an incorrect signature for your `validate` function. Modern Hapi (v17+) and `hapi-auth-jwt2` expect the `validate` function to be `async` and return an object `{ isValid, credentials }`, rather than accepting and calling a callback.","error":"cb is not a function in hapi-auth-jwt2"}],"ecosystem":"npm","meta_description":null}