跳到主要内容
ecdsa.com
Node.js

jsonwebtoken (Node.js)

Auth0 的 jsonwebtoken,Node.js 中安装量最大的 JWT 包:基于 node:crypto 处理 HMAC、RSA 和 ECDSA 令牌,从第 9 版起算法检查与密钥类型绑定——但不支持 EdDSA。
许可证
MIT
检查的版本
9.0.3 ·
源代码
github.com/auth0/node-jsonwebtoken
文档
github.com/auth0/node-jsonwebtoken#readme

兼容性概览

JOSE 与 JWT

JWS 算法
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512

jsonwebtoken 提供三个调用来签名和验证 JSON Web Token:jwt.sign()、jwt.verify() 和 jwt.decode()。它通过 jws 和 jwa 包处理 JWS 层,用 node:crypto 完成密码学运算,因此密钥可以是 PEM 字符串、Buffer 或 KeyObject 实例。jwt.decode() 只解析令牌——它从不检查签名,从它读取声明的代码会信任发送方写入的任何内容。

第 9 版堵住了经典的算法混淆途径,检查在 9.0.3 上证实了这一点:不传 algorithms 选项时,允许的算法列表由密钥类型决定;以公钥文本为密钥的 HS256 令牌会被拒绝;只有当你列出 none 且完全不提供密钥时,alg: none 才会通过。即便如此,仍应传入 algorithms——它明确写出了约定,而且即使密钥类型将来发生变化也依然有效。

支持的算法止于 RFC 7518 定义的集合:没有 EdDSA、Ed25519 或 ES256K。颁发者用 Ed25519 签名的令牌——在 jose、Go 和 Rust 技术栈中很常见——在这里无法验证,应改用 jose。ES256 还要求 P-256 密钥;以这个算法名用 P-384 密钥签名会直接抛出异常,而不会生成一个会被其他库拒绝的令牌。

令牌中的 ECDSA 签名是 JWS 强制要求的 64 字节原始 r‖s 格式。如果令牌是用 openssl dgst、Java 的 SHA256withECDSA 或云 KMS 手动拼装的,其签名就是 DER 格式,验证会报错 "ES256" signatures must be "64" bytes——把令牌粘贴到 JWT 调试器中可以查看签名长度,再用 DER ⇄ 原始格式转换器修复。

有两个默认行为让很多团队感到意外,一个比预想的更严格,一个比预想的更宽松:clockTolerance 为零,因此服务器之间只要有几秒的时钟漂移,就会报出 jwt expired;exp 是可选的,因此签发时不带它的令牌永远不会过期。签名时应设置 expiresIn,验证时应设置 maxAge 或显式要求 exp;可以用 JWT 密钥检测工具检查 HMAC 密钥。

事实及其依据的检查

以下内容均非抄自文档。检查脚本 content/libraries/verify/jsonwebtoken/run.sh 于2026年10月20日在容器镜像 node:24.22.0-bookworm-slim 中运行了 jsonwebtoken (Node.js) 9.0.3(运行时为 Node.js 24.22.0);本页内容必须与它的输出一致,每条事实都列出了对应的输出行。

  • JWS 算法

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512

    在检查中,HS256/384/512、RS256/384/512、PS256/384/512 和 ES256/384/512 的签名与验证均成功。EdDSA、Ed25519、Ed448、ES256K 和 ML-DSA 在签名时被拒绝。

    检查记录
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512
    evidence jws-algorithms: ES256K: sign throws Error: "algorithm" must be a valid string enum value
    evidence jws-algorithms: EdDSA: sign throws Error: "algorithm" must be a valid string enum value
    evidence jws-algorithms: Ed25519: sign throws Error: "algorithm" must be a valid string enum value
    evidence jws-algorithms: Ed448: sign throws Error: "algorithm" must be a valid string enum value
    evidence jws-algorithms: ML-DSA-44: sign throws Error: "algorithm" must be a valid string enum value
  • ES256 签名编码

    raw

    令牌中的 ES256 签名是 64 字节的原始 r‖s,符合 RFC 7518 的要求;该库会把 node:crypto 生成的 DER 转换成这种格式。

    检查记录
    fact jws-ecdsa-encoding = raw
  • JWS 中的 DER 签名

    rejected

    ES256 签名被重新编码为 DER 的令牌会报错 "ES256" signatures must be "64" bytes, saw "72"(这个数字是 DER 数据块的长度)。

    检查记录
    fact jws-der-signature = rejected
    evidence jws-der-signature: TypeError: "ES256" signatures must be "64" bytes, saw "72"
  • 算法允许列表

    from-key

    不传 algorithms 时,验证只允许与密钥相符的算法:HS256 令牌用共享密钥验证通过,ES256 令牌用 EC 公钥验证通过,而用 EC 密钥验证 RS256 令牌时报错 invalid algorithm。

    检查记录
    fact jwt-algorithm-allowlist = from-key
    evidence jwt-algorithm-allowlist: RS256 token against an EC key: JsonWebTokenError: invalid algorithm
  • 未签名的令牌(alg none)

    opt-in

    只要提供了密钥,未签名的令牌就会被拒绝,报错 jwt signature is required;只有当 algorithms 包含 none 且密钥参数为空时,它才能验证通过。

    检查记录
    fact jwt-alg-none = opt-in
    evidence jwt-alg-none: with a key: JsonWebTokenError: jwt signature is required
    evidence jwt-alg-none: algorithms ["none"] and no key: verified
  • 把公钥用作 HMAC 密钥

    rejected

    以公钥 PEM 文本为 HMAC 密钥的 HS256 令牌,无论不提供算法列表(invalid algorithm),还是设置 algorithms: ["HS256"](secretOrPublicKey must be a symmetric key when using HS256),都会被拒绝。

    检查记录
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: no list: JsonWebTokenError: invalid algorithm
    evidence jwt-hmac-public-key: algorithms ["HS256"]: JsonWebTokenError: secretOrPublicKey must be a symmetric key when using HS256
  • 按 alg 检查曲线

    enforced

    用 P-384 密钥签名 ES256 时抛出 "alg" parameter "ES256" requires curve "prime256v1".——ES256、ES384 和 ES512 分别绑定 P-256、P-384 和 P-521。

    检查记录
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: Error: "alg" parameter "ES256" requires curve "prime256v1".
  • 默认时钟偏差

    0s

    默认没有容差:三秒前过期的令牌被拒绝。以秒为单位设置 clockTolerance,即可容许时钟漂移。

    检查记录
    fact jwt-clock-skew = 0s
  • 是否要求过期时间声明

    no

    不含 exp 声明的令牌验证通过;只有当该声明存在或设置了 maxAge 时,才会检查过期时间。

    检查记录
    fact jwt-exp-required = no

用法

签发并验证 ES256 令牌,在验证端固定算法、颁发者和受众。
import { generateKeyPairSync } from "node:crypto";
import jwt from "jsonwebtoken";

const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });

const token = jwt.sign({ sub: "user-42" }, privateKey, {
  algorithm: "ES256",
  expiresIn: "10m",
  issuer: "https://auth.example.com",
  audience: "api",
});

// Pin the algorithm, issuer and audience instead of trusting the token header.
const claims = jwt.verify(token, publicKey, {
  algorithms: ["ES256"],
  issuer: "https://auth.example.com",
  audience: "api",
});

console.log("sub:", claims.sub);

代码片段测试工具会在容器镜像 node:24.22.0-bookworm-slim 中原样运行每个示例,只要输出不匹配,运行就会失败。

环境准备
npm init -y >/dev/null && npm install --no-audit --no-fund jsonwebtoken@9.0.3
命令
node usage.mjs
输出必须匹配(正则表达式)
sub: user-42

库