Authlib は Flask、Django、Starlette、httpx 向けの本格的な OAuth 2.0 と OpenID Connect のツールキットで、authlib.jose はその基盤となった JWS、JWE、JWK、JWT の層です。1.9.1 でこれをインポートすると authlib.jose module is deprecated, please use joserfc instead. が出力されます。メンテナーは JOSE のコードを別パッケージの joserfc に移しており、旧モジュールは互換性のために 2.0 まで残されます。既存のコードは引き続き動作しますが、新しいコードでは joserfc を使うべきです。
最もつまずきやすいのは、decode() が署名しか確認しないという点です。1 時間前に期限切れになったトークンも、decode() からは何の問題もなく返ってきました。有効期限、発行者、オーディエンスが確認されるのは claims.validate() を呼び出したときだけです。その際は claims_options で exp と iss を必須に指定してください。指定しないと、これらのないトークンも通ってしまいます。validate() に指定しない限り、時刻のずれの許容(leeway)はゼロです。
アルゴリズムの扱いは、どのオブジェクトを使うかによって異なります。モジュールレベルの jwt は既知のアルゴリズムをすべて受け入れて鍵の種類で選ぶため、EC 鍵に対して RS256 トークンを渡すと、鍵のインポートの段階で失敗しました。JsonWebToken(["ES256"]) のインスタンスは、列挙したものだけを許可します。none を列挙するだけで署名のないトークンが検証を通るため、設定値がそのリストに入ることは決してないようにしてください。PEM の公開鍵に見える HMAC 鍵は This key may not be safe to import で拒否され、ES256 は P-384 の鍵を拒否します。
1.9.1 で対応しているアルゴリズムは HS、RS、PS、ES の各ファミリーと ES256K、EdDSA で、Ed25519 や Ed448 という名前には対応していません。ES256 署名は 64 バイトの生の r‖s で、DER 署名は bad_signature で失敗します。その診断には JWT デバッガーと DER ⇄ 生形式の変換ツールが役立ちます。ID プロバイダーのトークンと鍵がどのような形をしているかを確認するには、OIDC トークンバリデーターと JWKS チェッカーを使ってください。
サンプルでは、制限した JsonWebToken インスタンスを使い、クレームを明示的に検証しています。この 2 つは、モジュールレベルの API では省かれている手順です。