python-jose は JWS、JWE、JWK、JWT を実装しており、バックエンドを差し替えられます(純粋な Python 実装の ecdsa、pycryptodome、cryptography)。チェックでは cryptography の extra をインストールしました。長年の FastAPI や Flask のチュートリアルによって広く普及しましたが、開発のペースは遅く、3.4.0(2025年2月)は 3.3.0 から 4 年近く後のリリースでした。新しいプロジェクトでは通常、代わりに PyJWT、jwcrypto、joserfc のいずれかが選ばれます。
jwt.decode() では algorithms が省略可能で、省略するとアルゴリズムはトークンのヘッダーから決まります。2026年9月に公開され、3.5.0 でも修正されていないアドバイザリ GHSA-3qf3-8w2g-rqmx(CVE-2026-85394)と組み合わさると、これは悪用可能です。公開鍵を HMAC シークレットとして使うことを防ぐガードは PEM と OpenSSH のテキストを認識しますが、同じ鍵の DER バイト列は認識しません。チェックではこれを再現できました。DER の公開鍵を HMAC 鍵とした HS256 トークンは、algorithms を省略するとその鍵で検証を通り、algorithms=["ES256"] を渡すと The specified alg value is not allowed で拒否されました。algorithms は必ず渡し、公開鍵は PEM 文字列のまま保持し、シークレットは JWT シークレットチェッカーで確認してください。
対応アルゴリズムは Python ライブラリの中で最も古い構成で、HS、RS、ES の各ファミリーだけです。PS256、EdDSA、ES256K では Algorithm … not supported. が発生するため、Ed25519 や RSA-PSS に移行したプロバイダーのトークンは検証できません。また、ES256 は P-256 に限定されていません。P-384 鍵で ES256 ヘッダーの 96 バイトの署名が生成され、python-jose はこれを検証しましたが、jose や PyJWT などの他のライブラリは拒否します。
ES256 署名は 64 バイトの生の r‖s で、DER 署名は Signature verification failed. で失敗します。トークンがどちらの形式かは JWT デバッガーで確認できます。サンプルのように options で require_exp と leeway を設定しない限り、exp は省略可能で、時刻のずれの許容(leeway)はゼロです。
署名のないトークンは、algorithms=["none"] を指定しても Unable to find an algorithm for key で拒否されました。