本文へスキップ
ecdsa.com
Python

Authlib (authlib.jose)

Authlib の JOSE モジュールは、Authlib の OAuth と OpenID Connect のクライアントとサーバーの基盤となるトークン層です。1.9 で非推奨となって joserfc への移行が勧められており、クレームを検証せずにデコードし、alg: none もリストに含めれば許可します。
ライセンス
BSD-3-Clause
確認したバージョン
1.9.1 ·
ソースコード
github.com/authlib/authlib
ドキュメント
docs.authlib.org/en/latest/

互換性の概要

JOSE と JWT

JWS アルゴリズム
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

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 では省かれている手順です。

事実とその根拠となるチェック

以下の内容はドキュメントからの転記ではありません。2026年10月20日に、チェック content/libraries/verify/authlib/run.sh がコンテナイメージ python:3.14.8-slim-trixie 内で Authlib (authlib.jose) 1.9.1 を cryptography 50.0.2 で実行しました。このページの内容はその出力と一致していなければならず、各事実には該当する出力行を示しています。

  • JOSE モジュールのステータス

    deprecated

    1.9.1 で authlib.jose をインポートすると、authlib.jose module is deprecated, please use joserfc instead. が出力されます。

    チェックによる記録
    fact jose-module-status = deprecated
    evidence jose-module-status: authlib.jose module is deprecated, please use joserfc instead.
  • JWS アルゴリズム

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

    HS、RS、PS、ES の 256/384/512 ビット、ES256K、EdDSA で署名と検証ができました。Ed25519 と Ed448 では UnsupportedAlgorithmError が発生しました。

    チェックによる記録
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, ES256K, EdDSA
    evidence jws-algorithms: Ed25519: UnsupportedAlgorithmError: unsupported_algorithm: 
    evidence jws-algorithms: Ed448: UnsupportedAlgorithmError: unsupported_algorithm: 
    evidence jws-algorithms: algorithms the module-level authlib.jose.jwt accepts: ES256, ES256K, ES384, ES512, EdDSA, HS256, HS384, HS512, PS256, PS384, PS512, RS256, RS384, RS512
  • ES256 署名のエンコーディング

    raw

    ES256 署名は 64 バイトの生の r‖s です。

    チェックによる記録
    fact jws-ecdsa-encoding = raw
  • JWS 内の DER 署名

    rejected

    DER エンコードの ES256 署名を持つトークンは BadSignatureError: bad_signature で失敗します。

    チェックによる記録
    fact jws-der-signature = rejected
    evidence jws-der-signature: BadSignatureError: bad_signature: 
  • アルゴリズムの許可リスト

    from-key

    モジュールレベルの jwt は、鍵の種類に対応するアルゴリズムであれば何でも受け入れます。ES256 トークンは EC 鍵で検証を通り、EC 鍵に対する RS256 トークンは Invalid data for importing key で失敗しました。

    チェックによる記録
    fact jwt-algorithm-allowlist = from-key
    evidence jwt-algorithm-allowlist: authlib.jose.jwt.decode on ES256: verified; RS256 token with an EC key: ValueError: Invalid data for importing key
  • 署名なしトークン(alg none)

    opt-in

    デフォルトの jwt は alg: none に対して UnsupportedAlgorithmError を発生させますが、JsonWebToken(["none"]) では署名のないトークンが検証を通ります。

    チェックによる記録
    fact jwt-alg-none = opt-in
    evidence jwt-alg-none: default jwt with an EC key: UnsupportedAlgorithmError: unsupported_algorithm: 
    evidence jwt-alg-none: JsonWebToken(['none']): verified
  • HMAC シークレットとして使われる公開鍵

    rejected

    PEM の公開鍵を HS256 の鍵として使うと、デフォルトのオブジェクトでも制限したインスタンスでも ValueError: This key may not be safe to import が発生します。

    チェックによる記録
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: JsonWebToken(['HS256']) with PEM text as key: ValueError: This key may not be safe to import
    evidence jwt-hmac-public-key: default jwt with PEM text as key: ValueError: This key may not be safe to import
  • alg と曲線の照合

    enforced

    P-384 の鍵で ES256 の署名を行うと Key for "ES256" not supported, only "P-256" allowed が発生します。

    チェックによる記録
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: ValueError: Key for "ES256" not supported, only "P-256" allowed
  • デコード時のクレーム検証

    no

    decode() は 1 時間前に期限切れになったトークンのクレームを返しました。exp、nbf、iss、aud を確認するのは claims.validate() だけです。

    チェックによる記録
    fact jwt-claims-validated-on-decode = no
    evidence jwt-claims-validated-on-decode: decode() of a token expired an hour ago without validate(): returned claims
  • デフォルトのクロックスキュー

    0s

    validate() はデフォルトで時刻のずれを許容しません。3 秒前に期限切れになったトークンは拒否されました。

    チェックによる記録
    fact jwt-clock-skew = 0s
  • 有効期限クレームの要否

    no

    exp のないトークンも validate() を通りました。これを必須にするには、claims_options で指定してください。

    チェックによる記録
    fact jwt-exp-required = no

使い方

ES256 に制限したインスタンスで ES256 トークンを発行して検証し、その後クレームを明示的に検証します。
import time

from authlib.jose import JsonWebKey, JsonWebToken

key = JsonWebKey.generate_key("EC", "P-256", is_private=True)
public_jwk = key.as_dict(is_private=False)

# A JsonWebToken instance restricted to ES256 instead of the permissive module-level jwt.
es256 = JsonWebToken(["ES256"])
token = es256.encode({"alg": "ES256"}, {"sub": "user-42", "iss": "https://auth.example.com", "exp": int(time.time()) + 600}, key)

claims = es256.decode(
    token,
    public_jwk,
    claims_options={"iss": {"essential": True, "value": "https://auth.example.com"}, "exp": {"essential": True}},
)
claims.validate(leeway=30)  # decode() checks only the signature; validate() checks the claims
print("sub:", claims["sub"])

スニペットのテストハーネスは、すべてのサンプルをコンテナイメージ python:3.14.8-slim-trixie 内でそのまま実行し、出力が一致しなければ実行は失敗します。

セットアップ
pip install --quiet --root-user-action=ignore Authlib==1.9.1 cryptography==50.0.2
コマンド
python usage.py
一致すべき出力(正規表現)
sub: user-42

ライブラリ