跳到主要内容
ecdsa.com
jose (JavaScript)JWT 库

错误信息

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 从不猜测字符串里装的是什么。

原因

修复方法

  1. 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. 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. 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"] });

相关错误

浏览完整的签名错误库