@fastify/jwt

JWT authentication plugin for Fastify, decorating routes with sign, verify, and decode utilities built on fast-jwt.

Library
npm
v10.2.2
584stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
83/100Excellent
Development Activity76
Maintenance84
Community84
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture78
Code Quality92
Innovation85
Learning Curve55

@fastify/jwt is the official Fastify plugin for adding JSON Web Token authentication to a Fastify application. Once registered with a secret (or a key-resolution function), it decorates the Fastify instance with jwt.sign, jwt.verify, and jwt.decode, and adds request.jwtVerify()/request.jwtDecode() and reply.jwtSign() so tokens can be issued and checked directly inside route handlers and hooks. Internally it delegates the cryptographic work to fast-jwt, supporting the full range of HMAC, RSA, ECDSA, and EdDSA algorithms, while the plugin layer handles Fastify-specific concerns like error mapping, cookie-based token lookup, and typed configuration.

Beyond basic sign/verify, the plugin covers real-world authentication patterns: extracting tokens from either an Authorization header or a signed cookie (with automatic fallback), rejecting individual tokens via a trusted callback for denylisting, and a namespace option that lets multiple independently-configured JWT instances (for example, short-lived access tokens and long-lived refresh tokens) coexist on the same Fastify instance without naming collisions. It ships hand-written TypeScript definitions with declaration-merging support so payload and request.user shapes can be typed per-project.

What You Get

  • fastify.jwt.sign/verify/decode plus request.jwtVerify(), request.jwtDecode(), and reply.jwtSign() decorators added to every route
  • Support for HS*, RS*, ES*, PS*, and EdDSA algorithms via the underlying fast-jwt signer/verifier
  • Built-in cookie support for reading tokens from a signed or unsigned cookie, with automatic fallback to the Authorization header
  • A namespace option for running multiple independent JWT configurations (e.g. access + refresh tokens) side by side
  • Hand-written TypeScript definitions with declaration-merging hooks for typing the payload and request.user

Common Use Cases

  • Protecting REST routes with a bearer-token onRequest hook that populates request.user
  • Issuing short-lived access tokens and longer-lived refresh tokens stored in httpOnly cookies
  • Verifying externally-issued tokens (e.g. from Auth0 or another IdP) in verify-only mode using only a public key
  • Rotating signing keys via JWKS by resolving the verification key dynamically per request
  • Token denylisting/revocation checks via the trusted callback before trusting a decoded payload

Under The Hood

Architecture The plugin is a single index.js module wrapped with fastify-plugin (fp) so its decorators apply to the encapsulating scope rather than being isolated by Fastify’s plugin boundaries. On registration it validates options, builds a signer/decoder/verifier from fast-jwt, and decorates the Fastify instance with a jwt object (sign, verify, decode, cookie, lookupToken) plus request.jwtVerify/jwtDecode and reply.jwtSign. Async control flow for the multi-step verify path (resolve secret → verify token → check trusted callback) is sequenced with the steed waterfall helper rather than native async/await, preserving both callback- and Promise-based call signatures for consumers. The namespace option turns fastify.jwt into a map of per-namespace JWT instances instead of a single instance, guarding against duplicate namespace registration. A validatorCache Map caches verifiers by string key to avoid rebuilding them on every call when using default options with a static key.

Tech Stack A CommonJS Node.js module targeting Fastify 5.x (declared via the fastify-plugin metadata). Core dependencies are fast-jwt for all JWT cryptographic operations, fastify-plugin for correct plugin registration semantics, @fastify/error for creating typed, coded error classes, @lukeed/ms for parsing human-readable time spans ("10h", "7d") into milliseconds, and steed for callback-based async sequencing. Development tooling includes eslint with the neostandard config, c8 for coverage enforcement, and tstyche for TypeScript type-testing, with fastify, @fastify/cookie, and @fastify/rate-limit used only in integration tests.

Code Quality The test suite spans four files (jwt.test.js, jwt-async.test.js, namespace.test.js, options.test.js) totaling well over 3,000 lines, run against Node’s native node:test runner with a coverage gate of c8 --100 — full-coverage is enforced, not aspirational. TypeScript correctness is checked separately via tstyche against hand-written .d.ts definitions and dedicated .tst.ts type-assertion files. Errors are never generic: every failure path (missing token, bad request format, expired token, untrusted token, invalid signature) is mapped to a distinct FST_JWT_* error code created with @fastify/error, and errors bubbling up from fast-jwt are explicitly translated (wrapError) into these domain-specific types rather than leaked as-is. Naming is consistent and intention-revealing (checkAndMergeSignOptions, lookupToken), and CI runs via GitHub Actions on every change.

What Makes It Unique Relative to rolling JWT handling by hand with jsonwebtoken inside a Fastify app, this plugin’s main technical differentiators are its namespace mechanism for cleanly running multiple independent JWT configurations in one instance, its layered token-lookup fallback (header, then cookie, then a fully custom extractToken function), and its function-based secret resolution that transparently supports static secrets, JWKS-backed dynamic key lookup, and Promise- or callback-style resolution behind one consistent option. These are extensions of well-established JWT patterns rather than a novel approach to authentication itself.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search