エラーメッセージ
Signature verification failed (JWT::VerificationError)
別の表記
- JWT::VerificationError: Signature verification failed
捕捉されない場合、Ruby は発生場所に続けて「Signature verification failed (JWT::VerificationError)」と出力します。このテキストは ruby-jwt 2.10 と 3.3 で同じです。
ruby-jwt (Ruby) — JWT::VerificationError from JWT.decode
このエラーの意味
ruby-jwt はトークンをデコードし、渡された鍵で署名をチェックしましたが、そのチェックに失敗しました。トークンの形式は正しく、アルゴリズムも許可されています。鍵が署名者のものではないか、トークンが改ざんされています。`JWT::VerificationError` は `JWT::DecodeError` のサブクラスなので、`rescue JWT::DecodeError` は、不正な形式のトークンのエラーと一緒にこのエラーも捕捉します。
発生する理由
設定した鍵が署名者の鍵ではない
よくある別の環境の公開鍵、ローテーション後の古い鍵、または本番環境に紛れ込んだ開発用の構成によって起動のたびに再生成される鍵ペアです。
JWKS の中の誤った鍵で検証している
ときどき発行者の JWKS から `keys.first` を取り出す方法は、発行者が別の鍵で署名するまでしか機能しません。`jwks:` オプションを使い、ruby-jwt に `kid` で鍵を選択させてください。
HMAC シークレットが異なる
ときどきRails アプリはシークレットを `secret_key_base` から導出することがよくあります。別の値(または末尾に改行が付いた同じ値)を使うサービスは、異なる MAC を計算します。
修正方法
- 1.
発行者の JWKS から kid で鍵を選択する
`jwks:` オプションにはローダーを渡せます。トークンが未知の鍵を指定している場合、ruby-jwt は `kid_not_found: true` を付けてローダーを再度呼び出すため、ローテーションが反映されます。
ruby require "jwt" require "net/http" jwks_loader = ->(options) do @jwks = nil if options[:kid_not_found] && @jwks_loaded_at.to_i < Time.now.to_i - 300 # refetch on rotation @jwks ||= begin @jwks_loaded_at = Time.now.to_i JSON.parse(Net::HTTP.get(URI("https://issuer.example.com/.well-known/jwks.json"))) end end payload, header = JWT.decode(token, nil, true, algorithms: ["ES256"], jwks: jwks_loader, iss: "https://issuer.example.com/", verify_iss: true) - 2.
鍵が一致することを確かめる
双方の公開鍵のハッシュが一致すれば、鍵は原因から除外できます。その場合は、転送中にトークンが変更されていないかを調べてください。
bash openssl pkey -in issuer-private.pem -pubout | sha256sum openssl pkey -pubin -in configured-public.pem | sha256sum # must be identical