express-jwt、jose、jsonwebtoken、jwa 和 passport-jwt 都是用于处理 JSON Web Token(JWT)的 Node.js 库,但它们在抽象层级、功能范围和适用场景上有显著差异。jose 是一个全面支持 IETF JWT 相关标准(包括 JWS、JWE、JWK)的现代库;jsonwebtoken 提供了简洁的 JWT 签发与验证 API,被广泛采用;express-jwt 是专为 Express 框架设计的中间件,用于自动解析请求中的 JWT;passport-jwt 则是 Passport 认证框架的 JWT 策略插件;而 jwa 仅提供底层签名算法实现,目前已弃用。这些工具共同构成了 Node.js 生态中 JWT 处理的不同层次解决方案。
在现代 Web 应用中,JSON Web Token(JWT)是实现无状态身份验证的核心技术。Node.js 生态中有多个处理 JWT 的库,但它们的定位、能力与适用场景差异显著。本文将从实际工程角度,深入剖析 express-jwt、jose、jsonwebtoken、jwa 和 passport-jwt 的技术特性、使用方式与选型建议。
这些库并非处于同一抽象层级。有些是底层加密原语,有些是高层框架中间件,理解其职责边界是选型的第一步。
jwa:仅提供 签名算法(如 HS256、RS256)的原始实现,不处理 JWT 结构解析或验证逻辑。jsonwebtoken:完整的 JWT 签发与验证工具,支持常见算法、过期检查、自定义声明等,但依赖 jwa 或类似库处理底层加密。jose:全面支持 JWS、JWE、JWK、JWT 等 IETF 标准 的现代库,兼容性广,安全性高,API 设计更贴近规范。express-jwt:专为 Express 设计的 中间件,内部通常调用 jsonwebtoken,用于自动解析请求头中的 JWT 并挂载到 req.user。passport-jwt:Passport 认证策略的一种,用于 集成 JWT 到 Passport 的认证流程 中,适合已有 Passport 架构的项目。⚠️ 注意:
jwa已被标记为 deprecated(见 npm 页面),官方建议迁移到jose或node:crypto。新项目不应再使用jwa。
jsonwebtoken 签发和验证const jwt = require('jsonwebtoken');
// 签发
const token = jwt.sign({ id: 123, role: 'user' }, 'secret', { expiresIn: '1h' });
// 验证
try {
const payload = jwt.verify(token, 'secret');
console.log(payload); // { id: 123, role: 'user', iat: ..., exp: ... }
} catch (err) {
console.error('Invalid token');
}
jose 签发和验证(现代 API)import { SignJWT, jwtVerify } from 'jose';
// 签发(需使用 CryptoKey)
const secret = new TextEncoder().encode('secret');
const token = await new SignJWT({ id: 123, role: 'user' })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('1h')
.sign(secret);
// 验证
try {
const { payload } = await jwtVerify(token, secret);
console.log(payload);
} catch (err) {
console.error('Invalid token');
}
express-jwt 作为中间件const express = require('express');
const jwt = require('express-jwt');
const app = express();
app.use(
jwt({ secret: 'secret', algorithms: ['HS256'] }).unless({ path: ['/login'] })
);
app.get('/profile', (req, res) => {
// req.user 已自动填充
res.json(req.user);
});
passport-jwt 集成到 Passportconst JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
passport.use(new JwtStrategy({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secret'
}, (payload, done) => {
// 自定义用户查找逻辑
User.findById(payload.id, (err, user) => {
if (err) return done(err, false);
if (user) return done(null, user);
else return done(null, false);
});
}));
app.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
res.json(req.user);
});
jwa(已弃用)示例(仅作参考)// 不推荐在新项目中使用
const jwa = require('jwa');
const hmac = jwa('HS256');
const signature = hmac.sign('header.payload', 'secret');
jose 是目前 最符合 IETF RFC 标准 的库,完整支持 JWA、JWK、JWE 等规范,对密钥管理、算法限制、令牌结构有严格校验,适合高安全要求场景。jsonwebtoken 虽广泛使用,但历史上存在若干安全漏洞(如算法混淆攻击),需开发者显式指定 algorithms 参数以避免风险。express-jwt 和 passport-jwt 的安全性取决于其底层依赖(通常是 jsonwebtoken),因此同样需注意配置。jwa 因不再维护,存在未修复的安全隐患,应避免使用。express-jwt 提供开箱即用的体验。passport-jwt 可无缝集成,复用现有认证流程。jose 是首选。jsonwebtoken 仍是一个可靠选择(但务必正确配置)。jwa。jsonwebtoken 迁移到 jose:需重写签发/验证逻辑,使用 SignJWT 和 jwtVerify,并确保密钥以 CryptoKey 形式提供。express-jwt 迁移到 jose:可自定义中间件,用 jose 替代内部验证逻辑。| 包名 | 抽象层级 | 是否维护 | 标准兼容性 | 典型用途 |
|---|---|---|---|---|
jose | 高(完整 JWT 套件) | ✅ 是 | ⭐⭐⭐⭐⭐(IETF 全面支持) | 高安全、标准合规项目 |
jsonwebtoken | 中(签发/验证工具) | ✅ 是 | ⭐⭐⭐(基础 JWT) | 快速实现、中小型项目 |
express-jwt | 高(Express 中间件) | ✅ 是 | 依赖 jsonwebtoken | Express 应用快速集成 |
passport-jwt | 高(Passport 策略) | ✅ 是 | 依赖 jsonwebtoken | 已使用 Passport 的项目 |
jwa | 低(签名算法原语) | ❌ 否(已弃用) | ⭐(仅算法) | 不应在新项目中使用 |
jose:它代表了 JWT 处理的现代方向,安全性强,标准兼容性好,长期维护有保障。jsonwebtoken:但务必显式指定 algorithms,避免使用字符串密钥以外的不安全配置。express-jwt 和 passport-jwt 本质是胶水层,其价值在于简化集成,而非提供核心能力。jwa:它的时代已经结束。选择 jose 如果你需要一个符合最新 IETF 标准、安全性高且功能全面的 JWT 库,特别是当你需要处理 JWK(JSON Web Key)、JWE(加密令牌)或对算法和密钥管理有严格要求时。它是新项目的首选,尤其适合对安全性和标准兼容性有高要求的场景。
不要在新项目中选择 jwa —— 该包已在 npm 上被官方标记为弃用(deprecated),不再维护。它仅提供底层签名算法,缺乏完整的 JWT 结构处理能力,且存在潜在安全风险。应优先评估 jose 或直接使用 Node.js 内置的 crypto 模块替代。
选择 jsonwebtoken 如果你追求简单直接的 JWT 签发和验证功能,且项目不需要 JWE 或复杂的密钥集支持。它 API 简洁、社区广泛,但必须显式指定 algorithms 参数以防止算法混淆攻击,适合快速开发和维护成本敏感的项目。
选择 passport-jwt 如果你的应用已基于 Passport 实现认证体系,并希望将 JWT 作为其中一种认证策略无缝集成。它允许你复用 Passport 的中间件模式和用户序列化逻辑,适合已有 Passport 架构的项目,但会引入 Passport 的额外依赖和概念。
选择 express-jwt 如果你正在使用 Express 框架,并希望快速集成一个能自动解析 Authorization 头中 JWT 的中间件,将解码后的载荷挂载到 req.user。它适合不需要复杂 JWT 逻辑的中小型 Express 应用,但要注意其安全性依赖于底层 jsonwebtoken 的正确配置。
jose is a JavaScript module for JSON Object Signing and Encryption, providing support for JSON Web Tokens (JWT), JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), JSON Web Key Set (JWKS), and more. The module is designed to work across various Web-interoperable runtimes including Node.js, browsers, Cloudflare Workers, Deno, Bun, and others.
If you want to quickly add JWT authentication to JavaScript apps, feel free to check out Auth0's JavaScript SDK and free plan. Create an Auth0 account; it's free!
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by becoming a sponsor.
jose has no dependencies and it exports tree-shakeable ESM1.
jose is distributed via npmjs.com, jsr.io, jsdelivr.com, and github.com.
example ESM import1
import * as jose from 'jose'
The jose module supports JSON Web Tokens (JWT) and provides functionality for signing and verifying tokens, as well as their JWT Claims Set validation.
jwtVerify function
SignJWT classThe jose module supports encrypted JSON Web Tokens and provides functionality for encrypting and decrypting tokens, as well as their JWT Claims Set validation.
jwtDecrypt functionEncryptJWT classThe jose module supports importing, exporting, and generating keys and secrets in various formats, including PEM formats like SPKI, X.509 certificate, and PKCS #8, as well as JSON Web Key (JWK).
The jose module supports signing and verification of JWS messages with arbitrary payloads in Compact, Flattened JSON, and General JSON serialization syntaxes.
The jose module supports encryption and decryption of JWE messages with arbitrary plaintext in Compact, Flattened JSON, and General JSON serialization syntaxes.
The following are additional features and utilities provided by the jose module:
The jose module is compatible with JavaScript runtimes that support the utilized Web API globals and standard built-in objects or are Node.js.
The following runtimes are supported (this is not an exhaustive list):
Please note that certain algorithms may not be available depending on the runtime used. You can find a list of available algorithms for each runtime in the specific issue links provided above.
| Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ | Runtime and Module type |
|---|---|---|---|---|
| v6.x | Security Policy | ✅ | ✅ | Universal2 ESM1 |
The algorithm implementations in jose have been tested using test vectors from their respective specifications as well as RFC7520.