本文へスキップ
ecdsa.com
PyJWT (Python)JWT ライブラリ

エラーメッセージ

Signature verification failed

PyJWT (Python) — jwt.exceptions.InvalidSignatureError

このエラーの意味

PyJWT はトークンの構造をデコードして署名のチェックを実行しましたが、そのチェックに失敗しました。署名が鍵とペイロードに一致しません。InvalidSignatureError は DecodeError のサブクラスなので、範囲の広すぎる except DecodeError では、これを解析の問題と誤って扱うおそれがありますが、実際には鍵と内容の不一致です。ES256 のトークンにはもう 1 つ注意点があります。JWS の署名は 64 バイトの生の r‖s 形式でなければならないため、ASN.1 DER を出力する自作の署名処理で作られたトークンは、鍵が正しくてもここで失敗します。

発生する理由

修正方法

  1. 1.

    両側で鍵のフィンガープリントを取る

    検証者が読み込んだ公開鍵の SHA-256 フィンガープリントを出力し、発行者のものと比較してください。違いがあれば、原因はそれで確定です。一致する場合は、トークンのバイト列のほうに問題があります。

    python
    import hashlib
    from cryptography.hazmat.primitives import serialization
    
    public_key = serialization.load_pem_public_key(pem_bytes)  # the key the verifier uses
    spki = public_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo)
    print(hashlib.sha256(spki).hexdigest())  # compare with the issuer's
  2. 2.

    破損を疑う前に kid を確認する

    検証前のヘッダーを読み、トークンが指定している鍵で検証していることを確かめてください。発行者の鍵が複数ある場合は、PyJWKClient を使って kid で鍵を特定してください。

    python
    import jwt
    
    header = jwt.get_unverified_header(token)
    print(header)  # {'alg': 'ES256', 'kid': '...'}
    
    from jwt import PyJWKClient
    key = PyJWKClient("https://issuer.example/.well-known/jwks.json") \
        .get_signing_key_from_jwt(token).key
    payload = jwt.decode(token, key, algorithms=["ES256"], audience="api://orders")

関連するエラー

署名エラーデータベースをすべて見る