python-jose implémente JWS, JWE, JWK et JWT avec des backends interchangeables (ecdsa en pur Python, pycryptodome ou cryptography) ; les essais ont installé l’extra cryptography. Des années de tutoriels FastAPI et Flask l’ont répandue, mais son développement est lent : la 3.4.0 (février 2025) est arrivée près de quatre ans après la 3.3.0, et les nouveaux projets choisissent plutôt PyJWT, jwcrypto ou joserfc.
algorithms est facultatif dans jwt.decode(), et sans lui l’algorithme est tiré de l’en-tête du jeton. Combiné à l’avis GHSA-3qf3-8w2g-rqmx (CVE-2026-85394), publié en septembre 2026 et non corrigé dans la 3.5.0, cela devient exploitable : le garde-fou qui empêche d’utiliser des clés publiques comme secrets HMAC reconnaît le texte PEM et OpenSSH, mais pas la même clé sous forme d’octets DER. Les essais l’ont reproduit : un jeton HS256 dont la clé HMAC était la clé publique DER a été vérifié avec cette clé quand algorithms était omis, et rejeté avec The specified alg value is not allowed dès que algorithms=["ES256"] était passé. Passez toujours algorithms, conservez les clés publiques sous forme de chaînes PEM et vérifiez vos secrets avec le vérificateur de secrets JWT.
Son jeu d’algorithmes est le plus ancien des bibliothèques Python : uniquement les familles HS, RS et ES. PS256, EdDSA et ES256K lèvent Algorithm … not supported., si bien que les jetons des fournisseurs passés à Ed25519 ou à RSA-PSS ne peuvent pas être vérifiés. ES256 n’est pas non plus lié à P-256 : une clé P-384 a produit, sous un en-tête ES256, une signature de 96 octets que python-jose a vérifiée, mais que d’autres bibliothèques, comme jose et PyJWT, refusent.
Les signatures ES256 font 64 octets en r‖s brut, et une signature DER échoue avec Signature verification failed. ; le débogueur JWT montre quelle forme contient un jeton. exp est facultatif et la marge de tolérance est nulle, sauf si vous définissez require_exp et leeway dans options, comme le fait l’exemple.
Les jetons non signés ont été rejetés avec Unable to find an algorithm for key, même avec algorithms=["none"].