错误信息
Key for the ES256 algorithm must be one of type CryptoKey, KeyObject, or JSON Web Key.
也可能输出为
- Key for the RS256 algorithm must be one of type CryptoKey, KeyObject, or JSON Web Key.
- Key for the HS256 algorithm must be one of type CryptoKey, KeyObject, JSON Web Key, or Uint8Array.
句中的算法随你的令牌而变化(`ES256`、`RS256`、`EdDSA`…)。对于 HMAC 算法,列表以“or Uint8Array”结尾。
jose (JavaScript) — TypeError from jwtVerify / SignJWT.sign
含义
你传给 jose 的值无法用作密钥——最常见的是 PEM 字符串或普通字符串形式的密钥。从版本 4 起,jose 只接受密钥对象:WebCrypto 的 `CryptoKey`、Node.js 的 `KeyObject`、JWK 对象,或者(对于 HMAC 算法)`Uint8Array`。文本格式必须先导入;jose 从不猜测字符串里装的是什么。
原因
直接传入了 PEM 字符串
常见从接受 PEM 文本的 jsonwebtoken 迁移过来的代码,常常把 `process.env.PUBLIC_KEY` 直接传给 `jwtVerify`。jose 要求先调用 `importSPKI`(公钥)、`importPKCS8`(私钥)或 `importX509`(证书)。
HMAC 密钥以字符串形式传入
常见对于 HS256/HS384/HS512,密钥必须是字节:`new TextEncoder().encode(secret)`。即使字符串本身就是正确的密钥,也会被拒绝。
传入的是 JWKS URL 字符串,而不是密钥集函数
偶见`"https://issuer/.well-known/jwks.json"` 是字符串,不是密钥。用 `createRemoteJWKSet(new URL(...))` 包装它,后者会返回 `jwtVerify` 所需要的函数。
缺少配置值
偶见未设置的环境变量会得到 `undefined`,它同样无法通过这项类型检查。在启动时校验配置,这样报错时就会指出缺少的是哪个变量。
修复方法
- 1.
在启动时一次性导入 PEM 密钥
`importSPKI` 和 `importPKCS8` 接收 PEM 文本以及密钥将要配合使用的算法,返回一个可以在每个请求中重复使用的 `CryptoKey`。
js import { importSPKI, importPKCS8, jwtVerify } from "jose"; const publicKey = await importSPKI(process.env.JWT_PUBLIC_KEY_PEM, "ES256"); // -----BEGIN PUBLIC KEY----- await jwtVerify(token, publicKey, { algorithms: ["ES256"] }); const privateKey = await importPKCS8(process.env.JWT_PRIVATE_KEY_PEM, "ES256"); // -----BEGIN PRIVATE KEY----- - 2.
把 HMAC 密钥编码为字节
HS256 使用至少 32 字节的随机密钥,并以 `Uint8Array` 传入。如果密钥以 base64 编码存储,就把它解码为字节,而不是对 base64 文本做编码。
js import { jwtVerify } from "jose"; const secret = new TextEncoder().encode(process.env.JWT_SECRET); // 32+ random bytes for HS256 await jwtVerify(token, secret, { algorithms: ["HS256"] }); - 3.
用密钥集验证,而不是 URL
对于来自身份提供商的令牌,传入 `createRemoteJWKSet` 返回的函数;jose 随后会根据每个令牌的 `kid` 选择密钥。
js import { createRemoteJWKSet, jwtVerify } from "jose"; const jwks = createRemoteJWKSet(new URL("https://issuer.example.com/.well-known/jwks.json")); await jwtVerify(token, jwks, { algorithms: ["ES256"] });