JWT が RS256 形式の署名で作成されている場合に、PyJWT で公開鍵を使って JWT の署名を検証しつつデコードする方法を説明します。
事前準備
PyJWT のドキュメントにあるように RSA の署名に対応するには、PyJWT と併せて依存パッケージの cryptography をインストールします。
$ pip install pyjwt
$ pip install cryptography
cryptography のビルドには Linux 環境では libffi-devel や openssl-devel といったパッケージをインストールしておく必要があるので、上記の $ pip install cryptography
でインストールに失敗した場合には、これらを確認してください。
OS X では環境変数の設定も必要で、割とややこしいです。
詳しくは cryptography のインストールドキュメントを参照してください。
公開鍵の例
pub_key.pem に以下のような公開鍵があるとします。
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAuDopA35ZLa1sgi2QTFbZjH63BrhXw4evehjDiLHrSc5s+jKMSqfd
6BLoQhN7jcOBnofQB/3rEoy6YXkW58lEtVmekQtYAHh11oB8TBBqzNZP1QxKXWjz
8Jely5bJZHztZEzfddDR7yVZF0VSEa0KjiHbqCdAqXKYuAzUMN4dFyS/q0JXvGAr
Jq/LXyVC3EptcZki02p3Nd6KDZHW7hcj+p0xgYNiGCHO7yLf3uHP+7pak5TW0dWf
MC9fl1/oYFILuasW7OV75+vJGs8d92joEC/Lx3S8+gi3z0CWMnCKrWiTtaAKAq8W
yp4Go8WczOQ1rP+bzDj7b/9M3xrjqY3F0wIDAQAB
-----END RSA PUBLIC KEY-----
ちなみにこの鍵データに「-----BEGIN RSA PUBLIC KEY-----」、「-----END RSA PUBLIC KEY-----」というフォーマット指示文が抜けていて、それが原因で検証に失敗していたことがあります。
PyJWT で JWT をデコードする
署名検証をしない場合
検証をしない場合のコードは次のようになります。
import jwt
encoded_jwt = 'JWTのデータ'
decoded_data = jwt.decode(encoded_jwt, verify=False)
このように jwt.decode() 関数の verify 引数に False を指定することによって署名の検証を省くことができます。verify 引数のデフォルト値は True なので明示的に False を指定する必要があります。
署名検証をする場合
次に署名を検証する場合のコードです。
from Crypto.PublicKey import RSA
import jwt
encoded_jwt = 'JWTのデータ'
rsa_public_key_pem = open('path/to/pub_key.pem', 'r').read()
rsa_key = RSA.importKey(rsa_public_key_pem)
key = rsa_key.exportKey()
decoded_data = jwt.decode(encoded_jwt, key=key, verify=True)
前述の公開鍵を読み込み、まず RSA.importKey() メソッドを通して RSA キーオブジェクトに変換します。この RSA キーオブジェクトの exportKey() メソッドから得られる鍵データを jwt.decode() 関数の key 引数に指定します。そして verify 引数に True を指定して署名検証を指示します。
RSA キーオブジェクトによる鍵データの変換をせずに RSA 公開鍵の文字列をそのまま jwt.decode() 関数の key 引数に指定すると ValueError: Could not unserialize key data.
というエラーになります。