koa-jwt
JWT authentication middleware that validates `Authorization: Bearer <token>` headers and populates `ctx.state.user` with the decoded payload.
Syntax
import jwt from 'koa-jwt';
app.use(jwt({ secret }));
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
options | object | Yes | Options: `secret` (string or Buffer, **required**), `key` (property name on `ctx.state`, default `"user"`), `passthrough` (allow unauthenticated requests), `algorithms` (allowed JWT algorithms, default `['HS256']`), `getToken` (custom token extractor function). |
Returns
function — Koa middleware that verifies the JWT and sets `ctx.state.user`.
Throws
HttpError— The token is missing (401) or invalid/expired (401).
Examples
import Koa from 'koa';
import jwt from 'koa-jwt';
import Router from '@koa/router';
import { sign } from 'jsonwebtoken';
const SECRET = process.env.JWT_SECRET ?? 'dev-secret';
const app = new Koa();
const router = new Router();
// Public route — no JWT required
router.post('/auth/token', async (ctx) => {
const token = sign({ sub: 'user:42', role: 'admin' }, SECRET, {
expiresIn: '1h',
});
ctx.body = { token };
});
// Protect all routes below with JWT
app.use(jwt({ secret: SECRET }));
router.get('/me', async (ctx) => {
ctx.body = ctx.state.user; // decoded payload
});
app.use(router.routes());
app.listen(3000);
Output
POST /auth/token → {"token":"eyJ..."}
GET /me (no token) → 401 Unauthorized
GET /me (valid token) → {"sub":"user:42","role":"admin","iat":...}
Notes
Mount the `jwt()` middleware after any public routes. Use `passthrough: true`
to allow unauthenticated access and check `ctx.state.user` manually. For
RS256 or ES256, pass the public key (PEM) as `secret`. Pair with an
allow-list middleware to support refresh-token invalidation.