Guides JWT

Comment je débogue une signature JWT invalide

Mon ordre pour mauvaise clé, algorithme, erreurs kid, rotation, encodage HMAC et octets du token modifiés sans désactiver la vérification.

Par JWTDecoder.toolsDernière vérification le 2026-09-16

Voix éditoriale : la première personne décrit le workflow documenté de JWTDecoder.tools ; JWTDecoder.tools est l’éditeur et l’auteur organisationnel.

Flux de diagnostic d’une signature JWT invalide
Je vérifie algorithme, issuer, kid et sélection de clé avant de modifier la vérification.

Pour invalid signature ou signature verification failed, je ne modifie ni payload ni configuration au hasard. Je conserve le compact JWT original puis j’isole algorithme, octets de clé, issuer, kid, JWKS et rotation.

Avec secret/public key connu, j’utilise JWT Signature Verifier ; avec JWKS, JWKS Validator.

Ce que signifie exactement invalid signature

Un JWS compact signe :

base64url(header).base64url(payload)

La vérification porte sur ces octets originaux. Un échec implique qu’algorithme, clé ou signed bytes ne correspondent pas au signer.

Cela ne signifie pas automatiquement token expiré, mauvaise audience ou permissions manquantes.

Je sépare immédiatement HMAC et RSA/EC

HS256/384/512 -> secret bytes / encoding / rotation
RS256/ES256   -> public key / kid / JWKS / issuer

La liste d’algorithmes autorisés vient de l’application, jamais du header non fiable.

HMAC : même texte visible, octets différents

Je vérifie :

  • UTF-8 raw vs secret décodé Base64 ;
  • newline dans une variable d’environnement ;
  • secrets différents dev/prod ;
  • rotation ;
  • espaces de copier/coller ;
  • secret trop faible.
const utf8 = new TextEncoder().encode(process.env.JWT_SECRET);
const b64 = Uint8Array.from(atob(process.env.JWT_SECRET), c => c.charCodeAt(0));

Ces deux clés peuvent être différentes.

RSA : format de clé et provenance

-----BEGIN PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
-----BEGIN RSA PUBLIC KEY-----

SPKI, certificat X.509 et PKCS#1 ne sont pas interchangeables dans toutes les libraries. Je convertis explicitement.

kid, JWKS et rotation

Je recherche kid uniquement dans le JWKS de confiance de l’issuer attendu. Causes typiques :

  • cache JWKS obsolète ;
  • nouvelle clé non chargée ;
  • ancienne clé retirée trop tôt ;
  • mauvais tenant/issuer ;
  • kty ou alg incompatible ;
  • kid dupliqué.

Voir JWT kid et key rotation.

Je distingue les messages par phase

JsonWebTokenError: invalid signature
JWSSignatureVerificationFailed
signature verification failed
kid not found
no applicable key found in the JSON Web Key Set

kid not found indique d’abord un échec de sélection, pas forcément une comparaison cryptographique ratée.

Je ne re-sérialise pas le payload

{"sub":"42","role":"user"}

et

{ "role": "user", "sub": "42" }

peuvent représenter les mêmes données mais pas les mêmes octets. La signature JWS couvre le compact input original.

Signature valide ≠ token acceptable

Après la signature, je valide encore :

  • exp/nbf ;
  • expected iss ;
  • expected aud ;
  • token type ;
  • scopes/roles.

J’utilise JWT Validator ou JWT Debugger.

Ce que je refuse comme « correctif »

  • désactiver la signature ;
  • accepter le alg choisi par le token ;
  • faire confiance à une jku arbitraire ;
  • modifier le payload et garder la signature ;
  • prendre la première clé JWKS ;
  • affaiblir un secret HMAC pour simplifier la configuration.

Matrice de diagnostic

SymptômeCouche probableVérifier
HS256 invalid signaturesecret/encodingbytes, Base64, newline
RS256 invalid signaturepublic keyissuer, PEM/JWK
kid not foundselection/cacheJWKS, rotation
algorithme non autorisépolicyallowlist, key type
après édition payloadsigned bytestoken original
signature ok + 401claimsexp/iss/aud/type

Mon workflow déterministe

  1. Je garde le compact JWT original.
  2. Je lis alg, kid, iss avec JWT Decoder.
  3. Je confirme les algorithmes permis par configuration.
  4. J’identifie la source de clé de confiance de l’issuer.
  5. En HMAC, je compare bytes/encoding exacts.
  6. En RSA/EC, je contrôle format, type et provenance.
  7. Avec JWKS, je vérifie kid, cache et rotation.
  8. Je vérifie le header.payload original.
  9. Ensuite je valide temps, issuer et audience.
  10. Je corrige key/config/deployment sans contourner la sécurité.

Invalid signature est un problème de confiance, pas un simple problème de parsing.

Je conserve les preuves minimales

Je note l’issuer attendu, le kid, l’algorithme, le type de clé et le composant qui a renvoyé l’erreur, sans recopier le JWT dans un ticket. Cette trace me permet de comparer un appel qui fonctionne avec un appel qui échoue et de déterminer si le problème vient de la sélection de clé, de la rotation ou de la configuration de vérification.

Sources et références

Guides associés