{"id":17445,"library":"koa-jwt2","title":"Koa JWT Authentication Middleware","description":"koa-jwt2 is Koa middleware designed for authenticating HTTP requests using JSON Web Tokens (JWT). It validates incoming JWTs and populates `ctx.state.user` (or a configurable property) with the decoded payload, making it available for subsequent middleware to handle authorization and access control. Key features include support for `audience`, `issuer`, and `expiration` validation, handling of base64 URL-encoded secrets, and verification with public/private key pairs. It integrates `koa-unless` for specifying unprotected paths and offers advanced options like custom token extraction via `getToken` and multi-tenancy support through an asynchronous secret function. The current stable version is 1.0.3. However, the package's GitHub repository has been archived, indicating it is no longer actively maintained, and thus its release cadence is effectively ceased. This makes it distinct from more actively developed alternatives, though its multi-tenancy secret resolution feature remains notable.","status":"abandoned","version":"1.0.3","language":"javascript","source_language":"en","source_url":"git://github.com/okoala/koa-jwt2","tags":["javascript","auth","authn","authentication","authz","authorization","http","jwt","token"],"install":[{"cmd":"npm install koa-jwt2","lang":"bash","label":"npm"},{"cmd":"yarn add koa-jwt2","lang":"bash","label":"yarn"},{"cmd":"pnpm add koa-jwt2","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Used for conditionally applying the middleware to specific routes, excluding others.","package":"koa-unless","optional":false}],"imports":[{"note":"This package is primarily CommonJS-oriented. Attempting ES module imports might lead to undefined `jwt` or module resolution errors, especially in older Node.js environments. The exported `jwt` is a function that returns the middleware.","wrong":"import jwt from 'koa-jwt2';","symbol":"jwt","correct":"const jwt = require('koa-jwt2');"},{"note":"The `jwt` variable itself is a function that, when called with options, returns the actual Koa middleware function to be used with `app.use`.","symbol":"jwt middleware function","correct":"app.use(jwt({ secret: 'your-secret' }));"},{"note":"The `unless` method is chained directly to the middleware returned by `jwt()`, as `koa-unless` is integrated internally. Do not try to import or use `unless` separately.","wrong":"app.use(unless({ path: ['/public'] })(jwt({ secret: 'your-secret' })));","symbol":"jwt().unless","correct":"app.use(jwt({ secret: 'your-secret' }).unless({ path: ['/public'] }));"}],"quickstart":{"code":"const Koa = require('koa');\nconst Router = require('@koa/router');\nconst jwt = require('koa-jwt2');\n\nconst app = new Koa();\nconst router = new Router();\n\nconst SECRET = process.env.JWT_SECRET || 'a-very-strong-secret-for-jwt-signing';\n\n// Middleware to generate a simple JWT for testing\nrouter.get('/token', async (ctx) => {\n  const jsonwebtoken = require('jsonwebtoken');\n  const token = jsonwebtoken.sign({ id: 1, name: 'testuser', admin: false }, SECRET, { expiresIn: '1h' });\n  ctx.body = { token };\n});\n\n// Protected route\nrouter.get('/protected', jwt({ secret: SECRET }).unless({ path: ['/token'] }), async (ctx) => {\n  if (!ctx.state.user) {\n    ctx.status = 401;\n    ctx.body = { message: 'Authentication required' };\n    return;\n  }\n  ctx.body = { message: `Hello, ${ctx.state.user.name}! You accessed a protected route.`, user: ctx.state.user };\n});\n\napp.use(router.routes()).use(router.allowedMethods());\n\nconst port = 3000;\napp.listen(port, () => {\n  console.log(`Server running on http://localhost:${port}`);\n  console.log('GET /token to get a JWT.');\n  console.log('GET /protected with Authorization: Bearer <token> header.');\n});","lang":"javascript","description":"This quickstart sets up a basic Koa application with two routes: `/token` to issue a JWT and `/protected` which is secured by `koa-jwt2`. It demonstrates how to configure the middleware with a secret, access the decoded user payload from `ctx.state.user`, and use the `unless` option to exclude the token issuance route from JWT validation. It requires `@koa/router` and `jsonwebtoken`."},"warnings":[{"fix":"Consider migrating to actively maintained alternatives like `koa-jwt` (ensure you check its maintenance status) or other modern Koa authentication solutions.","message":"The `koa-jwt2` package's GitHub repository has been archived, indicating it is no longer actively maintained. This means there will be no further bug fixes, security patches, or new features. Using this package in production carries increased risk, especially regarding potential unpatched security vulnerabilities.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"For base64, use `secret: Buffer.from('your-base64-secret', 'base64')`. For public keys, use `secret: fs.readFileSync('/path/to/public.pub')`.","message":"When using a base64 URL-encoded secret or a public key from a file, the `secret` option must be a Node.js `Buffer` object, not a string. Passing a string for these cases will lead to incorrect token verification.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use the `property` option to specify an alternative key, e.g., `jwt({ secret: '...', property: 'auth' })`, then access `ctx.state.auth`.","message":"By default, `koa-jwt2` attaches the decoded token payload to `ctx.state.user`. If you have other middleware or processes that rely on `ctx.state.user` for different purposes, this could lead to conflicts or unexpected overwrites. This can be particularly problematic if `ctx.state.user` is also used for session management.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure that if `credentialsRequired: false` is used, all downstream middleware and route handlers properly check for the presence and validity of `ctx.state.user` before granting access to sensitive resources or performing authenticated actions. Implement explicit authorization checks.","message":"The `credentialsRequired: false` option allows requests to proceed without a valid JWT. While useful for optional authentication, it can be a security footgun if not correctly understood. Routes using this option might mistakenly expose sensitive data if subsequent authorization logic is not robust.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Wrap asynchronous operations in `try...catch` blocks within the `secret` function and handle specific error types, potentially resolving with `null` or a default secret if appropriate for the application's security model, or re-throwing custom errors that can be caught by a more specific Koa error handler.","message":"When implementing multi-tenancy with an asynchronous `secret` function, ensure proper error handling within the function. If the `secret` function rejects or throws an error (e.g., 'missing_secret'), it will propagate up and typically result in a 500 Internal Server Error unless a global error handler is configured for Koa.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure you are using `const jwt = require('koa-jwt2');` as this package is primarily CommonJS. If using `type: 'module'` in `package.json`, you might need to use `import jwt from 'koa-jwt2'` if a default export is provided, but this specific package's primary usage is CJS.","cause":"Attempting to use an ES module import statement (`import jwt from 'koa-jwt2'`) in a CommonJS project, or incorrectly destructuring the `require` result.","error":"TypeError: jwt is not a function"},{"fix":"Verify the token's validity (signature, expiry, claims like audience/issuer). Check that the token is sent in the `Authorization: Bearer <token>` header, or configure `getToken` if it's in a query parameter or cookie. Ensure the `secret` configured matches the secret used to sign the token.","cause":"The JWT provided in the request was either missing, invalid (e.g., expired, wrong signature, incorrect audience/issuer), or the `credentialsRequired` option was set to `true` and no token was present.","error":"Error: Unauthorized"},{"fix":"Review the logic within your `secret` async function. Ensure that `data.getTenantByIdentifier` or equivalent logic correctly retrieves a tenant and its secret, and that any `reject(new Error('missing_secret'))` paths are intended and handled. Debug the `payload.iss` value to confirm it matches expected issuer identifiers.","cause":"In a multi-tenancy setup, the asynchronous `secret` function failed to resolve a secret for the given payload, often because the identified issuer or tenant was not found.","error":"Error: missing_secret"},{"fix":"Double-check the `secret` configuration. Ensure the string secret is identical, or that the `Buffer` for a base64 secret or public key is loaded correctly and contains the exact bytes. Verify that no encoding issues are corrupting the key or secret.","cause":"The secret or public key used by `koa-jwt2` to verify the token does not match the secret or private key used to sign the token. This often happens due to a mismatch between environments or incorrect key loading.","error":"JsonWebTokenError: invalid signature"}],"ecosystem":"npm","meta_description":null}