jose 涵盖整个 JOSE 家族——签名令牌和加密令牌、JWK 的导入与导出、本地和远程 JWK 集——在所有 JavaScript 运行时中都使用同一套 API。从第 6 版起,它的所有密码学运算都通过 WebCrypto 完成,因此密钥是 CryptoKey 对象(仍然接受 Node.js 的 KeyObject 实例),该库也继承了 WebCrypto 的曲线列表:ES256、ES384 和 ES512,EdDSA 和 Ed25519,以及 6.2.13 版中的 ML-DSA 算法(前提是运行时提供)。ES256K 和 Ed448 会被拒绝,报错 ERR_JOSE_NOT_SUPPORTED。
在关键之处,它的默认行为很严格。jwtVerify() 从不接受 alg: none——未签名的令牌只能通过单独的 UnsecuredJWT 类读取——而且一个密钥只绑定一个算法族,因此用 EC 公钥验证 HS256 令牌,或用 EC 密钥验证 RS256 令牌,都会报出 TypeError,而不会验证通过。ES256 也会拒绝 P-384 密钥。即便如此,仍应传入 algorithms:当密钥集包含多种密钥类型时,正是它防止颁发者悄悄切换算法。
有两个默认行为一严一松。clockTolerance 为零,这一点很严格;exp 却是可选的,这一点就宽松了:除非像示例那样把它列入 requiredClaims,否则不含过期时间的令牌也能验证通过。如果 JWS 的 ECDSA 签名是 DER 格式——用云 KMS 或 openssl dgst 手动拼装令牌时常见这种情况——会报出笼统的 signature verification failed,没有任何信息指向编码问题;JWT 调试器能让你一眼看出签名长度,DER ⇄ 原始格式转换器则可以修复它。
密钥导入是显式的:importSPKI 和 importPKCS8 接收 PEM 字符串——DER 字节会被拒绝,报错 "spki" must be SPKI formatted string——importX509 接收 PEM 证书,importJWK 接收 JWK。OpenSSL 默认写出的 SEC1 EC PRIVATE KEY 文件会被 importPKCS8 拒绝;需要先把它们转换为 PKCS#8,例如使用 JWK 转换器。
要验证身份提供商签发的令牌,可将 createRemoteJWKSet 与提供商的 jwks_uri 配合使用:它会缓存密钥,遇到未知的 kid 时重新获取,并对重新获取做速率限制。可以用 JWKS 检测查看提供商实际发布的内容。