Pular para o conteúdo
ecdsa.com
Python

Authlib (authlib.jose)

O módulo JOSE do Authlib, a camada de tokens por trás dos clientes e servidores OAuth e OpenID Connect do Authlib: descontinuado desde a 1.9 em favor do joserfc, ele decodifica sem validar as claims e permite alg: none assim que você o inclui na lista.
Licença
BSD-3-Clause
Versão verificada
1.9.1 ·
Código-fonte
github.com/authlib/authlib
Documentação
docs.authlib.org/en/latest/

Visão geral da compatibilidade

JOSE e JWT

Algoritmos JWS
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

O Authlib é um kit completo de OAuth 2.0 e OpenID Connect para Flask, Django, Starlette e httpx, e o authlib.jose é a camada de JWS, JWE, JWK e JWT sobre a qual ele foi construído. Importá-lo na versão 1.9.1 emite o aviso authlib.jose module is deprecated, please use joserfc instead.; os mantenedores moveram o código JOSE para o pacote separado joserfc, e o módulo antigo é mantido por compatibilidade até a 2.0. O código existente continua funcionando, mas é recomendável que código novo use o joserfc.

O detalhe que mais causa problemas é que decode() verifica apenas a assinatura. Um token que tinha expirado uma hora antes voltou de decode() sem nenhuma reclamação; a expiração, o emissor e o público-alvo só são verificados quando você chama claims.validate() — com claims_options marcando exp e iss como essenciais, porque, do contrário, um token sem elas também passa. A tolerância é zero, a menos que você passe uma a validate().

O tratamento dos algoritmos depende do objeto que você usa. O jwt do nível do módulo aceita todos os algoritmos que conhece e escolhe pelo tipo de chave, então um token RS256 apresentado com uma chave EC falhou na importação da chave; uma instância JsonWebToken(["ES256"]) permite apenas o que você listar. Incluir none na lista basta para que um token sem assinatura seja verificado, então nunca deixe que um valor de configuração acabe nessa lista. Chaves HMAC que parecem chaves públicas PEM são recusadas com This key may not be safe to import, e o ES256 recusa uma chave P-384.

Na 1.9.1, os algoritmos aceitos cobrem as famílias HS, RS, PS e ES, o ES256K e o EdDSA, mas não os nomes Ed25519 nem Ed448. As assinaturas ES256 são 64 bytes de r‖s brutos; uma assinatura DER falha com bad_signature, algo que o depurador de JWT e o conversor DER ⇄ bruto ajudam a diagnosticar. Para conferir como são os tokens e as chaves de um provedor de identidade, use o validador de tokens OIDC e o verificador de JWKS.

O exemplo usa uma instância restrita de JsonWebToken e valida as claims explicitamente — os dois passos que a API do nível do módulo deixa de fora.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/authlib/run.sh executou Authlib (authlib.jose) 1.9.1 em cryptography 50.0.2 na imagem de contêiner python:3.14.8-slim-trixie em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Status do módulo JOSE

    deprecated

    Importar authlib.jose na 1.9.1 emite authlib.jose module is deprecated, please use joserfc instead.

    Registrado pela verificação
    fact jose-module-status = deprecated
    evidence jose-module-status: authlib.jose module is deprecated, please use joserfc instead.
  • Algoritmos JWS

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512ES256KEdDSA

    Assinatura e verificação funcionaram com HS, RS, PS e ES em 256/384/512 bits, ES256K e EdDSA; Ed25519 e Ed448 lançaram UnsupportedAlgorithmError.

    Registrado pela verificação
    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
  • Codificação da assinatura ES256

    raw

    As assinaturas ES256 são 64 bytes de r‖s brutos.

    Registrado pela verificação
    fact jws-ecdsa-encoding = raw
  • Assinatura DER dentro de um JWS

    rejected

    Um token com uma assinatura ES256 codificada em DER falha com BadSignatureError: bad_signature.

    Registrado pela verificação
    fact jws-der-signature = rejected
    evidence jws-der-signature: BadSignatureError: bad_signature: 
  • Lista de algoritmos permitidos

    from-key

    O jwt do nível do módulo aceita qualquer algoritmo que implemente para o tipo de chave: um token ES256 foi verificado com uma chave EC, enquanto um token RS256 com a mesma chave EC falhou com Invalid data for importing key.

    Registrado pela verificação
    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
  • Tokens sem assinatura (alg none)

    opt-in

    O jwt padrão lança UnsupportedAlgorithmError para alg: none, mas JsonWebToken(["none"]) verifica um token sem assinatura.

    Registrado pela verificação
    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
  • Chave pública usada como segredo HMAC

    rejected

    Uma chave pública PEM usada como chave HS256 lança ValueError: This key may not be safe to import, tanto com o objeto padrão quanto com uma instância restrita.

    Registrado pela verificação
    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
  • Curva conferida com o alg

    enforced

    Assinar com ES256 usando uma chave P-384 lança Key for "ES256" not supported, only "P-256" allowed.

    Registrado pela verificação
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: ValueError: Key for "ES256" not supported, only "P-256" allowed
  • Claims validadas na decodificação

    no

    decode() retornou as claims de um token que tinha expirado uma hora antes; só claims.validate() verifica exp, nbf, iss e aud.

    Registrado pela verificação
    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
  • Tolerância padrão de diferença de relógio

    0s

    Por padrão, validate() não usa nenhuma tolerância: um token que tinha expirado três segundos antes foi rejeitado.

    Registrado pela verificação
    fact jwt-clock-skew = 0s
  • Claim de expiração obrigatória

    no

    Um token sem exp passou por validate(); marque essa claim como essencial em claims_options para exigi-la.

    Registrado pela verificação
    fact jwt-exp-required = no

Uso

Emita e verifique um token ES256 com uma instância restrita ao ES256 e depois valide as claims explicitamente.
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"])

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner python:3.14.8-slim-trixie, e a execução falha se a saída não corresponder.

Configuração
pip install --quiet --root-user-action=ignore Authlib==1.9.1 cryptography==50.0.2
Comando
python usage.py
A saída deve corresponder a (expressão regular)
sub: user-42

Bibliotecas