Перейти к содержимому
ecdsa.com
Python

Authlib (authlib.jose)

Модуль 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 — полноценный набор инструментов OAuth 2.0 и OpenID Connect для Flask, Django, Starlette и httpx, а authlib.jose — слой JWS, JWE, JWK и JWT, на котором он построен. В версии 1.9.1 импорт этого модуля выводит предупреждение authlib.jose module is deprecated, please use joserfc instead.; сопровождающие перенесли код JOSE в отдельный пакет joserfc, а старый модуль сохраняется для совместимости до версии 2.0. Существующий код продолжает работать, но новый код следует писать под joserfc.

Чаще всего подводит то, что decode() проверяет только подпись. decode() без возражений вернул токен, срок действия которого истёк час назад: срок действия, издатель и аудитория проверяются, только когда вы вызываете claims.validate(), причём в claims_options нужно пометить exp и iss как обязательные (essential), иначе токен без них тоже пройдёт проверку. Допустимое расхождение часов (leeway) равно нулю, если не передать его в validate().

Обработка алгоритмов зависит от того, какой объект вы используете. Объект jwt уровня модуля принимает любой известный ему алгоритм и выбирает его по типу ключа, поэтому проверка токена RS256 с ключом EC завершилась ошибкой уже на импорте ключа; экземпляр JsonWebToken(["ES256"]) допускает только перечисленные алгоритмы. Достаточно внести в этот список none, чтобы неподписанный токен прошёл проверку, поэтому никогда не допускайте, чтобы в список попало значение из конфигурации. Ключи HMAC, похожие на открытые ключи PEM, отклоняются с ошибкой This key may not be safe to import, а ключ P-384 для ES256 не принимается.

В версии 1.9.1 поддерживаются алгоритмы семейств HS, RS, PS и ES, а также ES256K и EdDSA, но не имена Ed25519 и Ed448. Подпись ES256 — это 64 байта в формате raw r‖s, а проверка подписи в DER завершается ошибкой bad_signature; найти причину помогут отладчик JWT и конвертер DER ⇄ raw. Чтобы посмотреть, как выглядят токены и ключи поставщика удостоверений, воспользуйтесь валидатором токенов OIDC и проверкой JWKS.

Пример использует экземпляр JsonWebToken с ограниченным списком алгоритмов и явно проверяет утверждения — это те два шага, которые пропускает API уровня модуля.

Факты и проверки, на которых они основаны

Ничего из приведённого ниже не скопировано из документации. 20 октября 2026 г. проверка content/libraries/verify/authlib/run.sh запустила Authlib (authlib.jose) 1.9.1 в среде cryptography 50.0.2 в образе контейнера python:3.14.8-slim-trixie; содержимое страницы должно совпадать с выводом проверки, а у каждого факта приведены соответствующие строки вывода.

  • Статус модуля 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 байта в формате raw r‖s.

    Что записала проверка
    fact jws-ecdsa-encoding = raw
  • Подпись в DER внутри JWS

    rejected

    Проверка токена с подписью ES256 в кодировке DER завершается ошибкой BadSignatureError: bad_signature.

    Что записала проверка
    fact jws-der-signature = rejected
    evidence jws-der-signature: BadSignatureError: bad_signature: 
  • Список разрешённых алгоритмов

    from-key

    Объект jwt уровня модуля принимает любой поддерживаемый алгоритм, подходящий к типу ключа: токен ES256 прошёл проверку с ключом EC, а проверка токена RS256 с тем же ключом EC завершилась ошибкой 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 по умолчанию выбрасывает UnsupportedAlgorithmError для alg: none, но с 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

    При подписи ES256 ключом P-384 выбрасывается 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() вернул утверждения токена, срок действия которого истёк час назад; только claims.validate() проверяет exp, nbf, iss и aud.

    Что записала проверка
    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() не допускает расхождения часов (leeway): токен, срок действия которого истёк 3 секунды назад, был отклонён.

    Что записала проверка
    fact jwt-clock-skew = 0s
  • Обязательное утверждение о сроке действия

    no

    Токен без exp прошёл validate(); чтобы требовать это утверждение, пометьте его в claims_options как обязательное (essential).

    Что записала проверка
    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

Библиотеки