エラーメッセージ
"alg" parameter "ES256" requires curve "prime256v1".
別の表記
- "alg" parameter "ES384" requires curve "secp384r1".
- "alg" parameter "ES512" requires curve "secp521r1".
`jwt.sign()` と `jwt.verify()` の両方がこのエラーをスローします。必要な曲線は OpenSSL の表記で示されます(`prime256v1`、`secp384r1`、`secp521r1`)。
jsonwebtoken (Node.js) — Error from jwt.sign() / jwt.verify() key validation (v9+)
このエラーの意味
渡された EC 鍵の曲線が、アルゴリズムが要求する曲線と異なります。JOSE では、各 ECDSA アルゴリズムがちょうど 1 つの曲線に結び付いています。ES256 は P-256(OpenSSL での名前は `prime256v1`)、ES384 は P-384(`secp384r1`)、ES512 は P-521(`secp521r1`)です。バージョン 9 以降の jsonwebtoken は、署名や検証の前に鍵の曲線を `alg` と照合するため、一致しない鍵は、他のどのライブラリも受け付けないトークンを生成するのではなく、最初の段階で拒否されます。
発生する理由
ES256 で secp256k1 の鍵を使っている
よくあるsecp256k1(Bitcoin、Ethereum)は別の 256 ビット曲線です。これに対応する JOSE のアルゴリズムは `ES256K`(RFC 8812)ですが、jsonwebtoken はサポートしていません。ES256 の「256」が指すのは SHA-256 と P-256 だけです。
ES256 で P-384 や P-521 の鍵を使っている
ときどきOpenSSL のデフォルト設定で生成した鍵、`ECC_NIST_P384` のようなクラウド KMS の鍵仕様、CA のプロファイルに基づく証明書の鍵は、より大きな曲線を使っていることがあります。鍵に合ったアルゴリズム(ES384/ES512)を選ぶか、P-256 の鍵を生成してください。
誤った鍵ファイルを読み込んでいる
ときどき1 つのシークレットストアに複数の鍵があり、サービスが別の用途の鍵を読み込んでいるケースです。たとえば TLS の鍵、SSH キー、別のシステム用の署名鍵などです。
修正方法
- 1.
鍵の曲線を出力する
`asymmetricKeyDetails.namedCurve` は、曲線を OpenSSL の名前で返します。これをトークンのヘッダーにあるアルゴリズムと比較してください。
js import { createPublicKey } from "node:crypto"; const key = createPublicKey(pem); console.log(key.asymmetricKeyType, key.asymmetricKeyDetails); // ec { namedCurve: 'prime256v1' } - 2.
鍵からアルゴリズムを決める
サイズの異なる鍵を併用している場合は、ES256 をハードコードするのではなく、鍵の曲線から JWS のアルゴリズムを選び、JWKS にも同じ `alg` を公開してください。
js const ALG_BY_CURVE = { prime256v1: "ES256", secp384r1: "ES384", secp521r1: "ES512" }; const alg = ALG_BY_CURVE[key.asymmetricKeyDetails.namedCurve]; if (!alg) throw new Error("this curve has no JWS algorithm in jsonwebtoken"); const token = jwt.sign(claims, key, { algorithm: alg, expiresIn: "10m" }); - 3.
ES256 が必要なら P-256 の鍵を生成する
ES256 は、JOSE ライブラリで最も広くサポートされている ECDSA アルゴリズムです。新しい P-256 の鍵ペアは、コマンド 1 つで生成できます。
bash openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out es256-private.pem openssl pkey -in es256-private.pem -pubout -out es256-public.pem