エラーメッセージ
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 ではなく鍵セットで検証する
ID プロバイダーが発行したトークンには、`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"] });