Message d’erreur
Signature verification failed
PyJWT (Python) — jwt.exceptions.InvalidSignatureError
Ce que cela signifie
PyJWT a décodé la structure du jeton et lancé la vérification de la signature, qui a échoué : la signature ne correspond pas à la clé et à la charge utile. InvalidSignatureError est une sous-classe de DecodeError : un except DecodeError trop large peut donc faire passer cette erreur pour un problème d’analyse, alors qu’il s’agit d’une non-concordance entre la clé et le contenu. Pour les jetons ES256, il existe une subtilité supplémentaire : la signature JWS doit être sous la forme brute r‖s de 64 octets, si bien que les jetons produits par des signataires faits maison qui émettaient de l’ASN.1 DER échouent ici même lorsque la clé est la bonne.
Pourquoi cela se produit
Une clé différente de celle de l’émetteur
fréquenteUne paire de clés remplacée lors d’une rotation alors que le vérificateur a gardé l’ancienne clé publique, un copier-coller du mauvais PEM, ou deux services qui lisent des versions différentes du secret dans le gestionnaire de secrets. Avec les émetteurs qui s’appuient sur un JWKS, une non-concordance de kid a le même effet.
Un signataire fait maison a produit une mauvaise signature
occasionnelleOutre le DER au lieu du r‖s brut, un signataire fait maison qui hache avec SHA-384 sous un en-tête ES256, ou qui signe le JSON au lieu du texte base64url header.payload, produit une signature bien formée qui ne se vérifie jamais. Une clé abîmée par la plomberie de la configuration n’aboutit pas ici : un PEM contenant des séquences \n littérales ne se charge pas et produit « Unable to load PEM file », et les guillemets ou l’indentation autour d’un PEM intact sont tolérés.
Jeton modifié après la signature
occasionnelleUn middleware qui resérialise le JSON de la charge utile ou modifie un seul caractère change les octets signés. La signature porte sur le texte base64url exact : les modifications cosmétiques ne sont pas cosmétiques. (Un remplissage base64 ajouté est rejeté plus tôt, avec « Invalid payload padding », et un jeton tronqué avec « Not enough segments ».)
Comment corriger l’erreur
- 1.
Calculer l’empreinte de la clé des deux côtés
Affichez une empreinte SHA-256 de la clé publique chargée par le vérificateur et comparez-la à celle de l’émetteur. Une différence met fin à la recherche ; une correspondance oriente plutôt vers les octets du jeton.
python import hashlib from cryptography.hazmat.primitives import serialization public_key = serialization.load_pem_public_key(pem_bytes) # the key the verifier uses spki = public_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo) print(hashlib.sha256(spki).hexdigest()) # compare with the issuer's - 2.
Vérifier kid avant de conclure à une corruption
Lisez l’en-tête non vérifié et assurez-vous que vous vérifiez avec la clé que désigne le jeton. Si l’émetteur a plusieurs clés, sélectionnez la clé par kid avec PyJWKClient.
python import jwt header = jwt.get_unverified_header(token) print(header) # {'alg': 'ES256', 'kid': '...'} from jwt import PyJWKClient key = PyJWKClient("https://issuer.example/.well-known/jwks.json") \ .get_signing_key_from_jwt(token).key payload = jwt.decode(token, key, algorithms=["ES256"], audience="api://orders")