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.