Aller au contenu
ecdsa.com
Java · Kotlin

JJWT (io.jsonwebtoken)

JJWT de Les Hazlewood, une bibliothèque JWT très utilisée pour Java et Android : la clé de vérification détermine l’algorithme acceptable, les jetons non signés exigent un analyseur unsecured() explicite et les clés HMAC faibles sont refusées d’emblée.
Licence
Apache-2.0
Version vérifiée
0.13.0 ·
Code source
github.com/jwtk/jjwt
Documentation
github.com/jwtk/jjwt#readme

Compatibilité en un coup d’œil

JOSE et JWT

Algorithmes JWS
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSA

Depuis la 0.12, JJWT expose une API fluide de construction et d’analyse (Jwts.builder()…signWith(key, alg) et Jwts.parser().verifyWith(key)…parseSignedClaims(token)), Jwts.SIG regroupant les algorithmes. La bibliothèque est livrée en trois artefacts : jjwt-api à la compilation, jjwt-impl et une liaison JSON comme jjwt-jackson à l’exécution. La 0.13.0 a réussi l’aller-retour avec HS, RS, PS et ES en 256/384/512 et EdDSA ; ES256K et les noms Ed25519 et Ed448 ne figurent pas dans Jwts.SIG.

L’analyseur déduit l’algorithme autorisé de la clé de vérification, et ses erreurs le disent clairement. Un jeton RS256 présenté à une clé publique EC et un jeton HS256 dont la clé HMAC était le texte PEM de la clé EC ont tous deux échoué avec UnsupportedJwtException, qui explique que la clé ne peut pas être utilisée pour cet algorithme. La protection tient au type de clé, pas à une liste : un analyseur configuré avec Keys.hmacShaKeyFor(pemBytes) a vérifié ce jeton falsifié ; ne construisez donc jamais de clés HMAC à partir de données qui pourraient être publiques.

Les jetons non signés sont refusés par parseSignedClaims avec un message qui cite la RFC 7518 §3.6, et ne peuvent être lus que via Jwts.parser().unsecured()…parseUnsecuredClaims. Les clés HMAC faibles ne vont jamais aussi loin : Keys.hmacShaKeyFor a rejeté une clé de 16 octets avec WeakKeyException, car la RFC 7518 exige des clés au moins aussi longues que le condensat. ES256 refuse une clé P-384 à la signature.

Deux valeurs par défaut demandent de l’attention. Aucune tolérance de décalage d’horloge n’est prévue (un jeton expiré depuis trois secondes a échoué) et exp est facultatif : définissez donc clockSkewSeconds et contrôlez l’expiration et l’émetteur comme le fait l’exemple. Les signatures ES256 sont au format r‖s brut de 64 octets ; une signature DER est signalée avec précision (Provided signature is 576 bits (72 bytes) but ES256 signatures must be exactly 512 bits (64 bytes)) : JJWT est l’une des rares bibliothèques à nommer le problème d’encodage. Inspectez les jetons dans le débogueur JWT et les clés HMAC avec le vérificateur de secrets JWT.

Pour gérer JWE et les jeux de clés JWK à grande échelle, comparez avec Nimbus JOSE + JWT.

Les faits et les vérifications qui les fondent

Rien de ce qui suit n’est copié d’une documentation. La vérification content/libraries/verify/jjwt/run.sh a exécuté JJWT (io.jsonwebtoken) 0.13.0 dans l’image de conteneur maven:3.9.16-eclipse-temurin-25 le 20 octobre 2026 ; la page doit correspondre à ce que la vérification a affiché, et chaque fait cite les lignes en question.

  • Algorithmes JWS

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSA

    Signature et vérification réussies avec HS, RS, PS et ES en 256/384/512 et EdDSA ; ES256K, Ed25519 et Ed448 ne figurent pas dans Jwts.SIG.

    Relevé par la vérification
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA
    evidence jws-algorithms: ES256K: not in Jwts.SIG
    evidence jws-algorithms: Ed25519: not in Jwts.SIG
    evidence jws-algorithms: Ed448: not in Jwts.SIG
  • Encodage des signatures ES256

    raw

    Les signatures ES256 font 64 octets, en r‖s brut.

    Relevé par la vérification
    fact jws-ecdsa-encoding = raw
  • Signature DER dans un JWS

    rejected

    Une signature ES256 encodée en DER échoue avec Provided signature is 576 bits (72 bytes) but ES256 signatures must be exactly 512 bits (64 bytes).

    Relevé par la vérification
    fact jws-der-signature = rejected
    evidence jws-der-signature: SignatureException: Unable to verify Elliptic Curve signature using provided ECPublicKey: Provided signature is 576 bits (72 bytes) but ES256 signatures must be exactly 512 bits (64 bytes) per [RFC 7518, Section 3.4 (validation)](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4).
  • Liste d’algorithmes autorisés

    from-key

    La clé de vérification détermine l’algorithme : un jeton RS256 présenté à une clé publique EC a échoué avec UnsupportedJwtException.

    Relevé par la vérification
    fact jwt-algorithm-allowlist = from-key
    evidence jwt-algorithm-allowlist: RS256 token, verifyWith(EC public key): UnsupportedJwtException: The parsed JWT indicates it was signed with the 'RS256' signature algorithm, but the provided sun.security.ec.ECPublicKeyImpl key may not be used to verify RS256 signatures.  Because the specified key reflects a specific and expected algorithm, and the JWT does not reflect this algorithm, it is likely that the JWT was not expected and therefore should not be trusted.  Another possibility is that the parser was provided the incorrect signature verification key, but this cannot be assumed for security reasons.
  • Jetons non signés (alg none)

    opt-in

    parseSignedClaims rejette les jetons non signés ; Jwts.parser().unsecured() avec parseUnsecuredClaims permet de les lire.

    Relevé par la vérification
    fact jwt-alg-none = opt-in
    evidence jwt-alg-none: parseSignedClaims with the EC key: UnsupportedJwtException: Unsecured JWSs (those with an 'alg' (Algorithm) header value of 'none') are disallowed by default as mandated by https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6. If you wish to allow them to be parsed, call the JwtParserBuilder.unsecured() method, but please read the security considerations covered in that method's JavaDoc before doing so. Header: {alg=none, typ=JWT}
    evidence jwt-alg-none: parser().unsecured().parseUnsecuredClaims: verified
  • Clé publique utilisée comme secret HMAC

    rejected

    Un jeton HS256 dont la clé HMAC était le texte PEM a été rejeté face à la clé publique EC, mais vérifié avec Keys.hmacShaKeyFor(pemBytes).

    Relevé par la vérification
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: verifyWith(EC public key): UnsupportedJwtException: The parsed JWT indicates it was signed with the 'HS256' signature algorithm, but the provided sun.security.ec.ECPublicKeyImpl key may not be used to verify HS256 signatures.  Because the specified key reflects a specific and expected algorithm, and the JWT does not reflect this algorithm, it is likely that the JWT was not expected and therefore should not be trusted.  Another possibility is that the parser was provided the incorrect signature verification key, but this cannot be assumed for security reasons.
    evidence jwt-hmac-public-key: verifyWith(Keys.hmacShaKeyFor(PEM bytes)): verified
  • Courbe vérifiée par rapport à alg

    enforced

    La signature ES256 avec une clé P-384 échoue : the 'ES256' algorithm requires EC Keys with 256 bits.

    Relevé par la vérification
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: SignatureException: Unable to compute ES256 signature. Cause: The provided Elliptic Curve signing key size (aka order bit length) is 384 bits (48 bytes), but the 'ES256' algorithm requires EC Keys with 256 bits (32 bytes) per [RFC 7518, Section 3.4](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4).
  • Décalage d’horloge toléré par défaut

    0s

    Aucune tolérance de décalage d’horloge par défaut : un jeton expiré depuis trois secondes a été rejeté.

    Relevé par la vérification
    fact jwt-clock-skew = 0s
  • Claim d’expiration obligatoire

    no

    Un jeton sans exp a été analysé avec succès.

    Relevé par la vérification
    fact jwt-exp-required = no
  • Secret HMAC court

    rejected

    Keys.hmacShaKeyFor a rejeté une clé de 16 octets avec WeakKeyException.

    Relevé par la vérification
    fact jwt-hmac-short-secret = rejected
    evidence jwt-hmac-short-secret: Keys.hmacShaKeyFor(16 bytes): WeakKeyException: The specified key byte array is 128 bits which is not secure enough for any JWT HMAC-SHA algorithm.  The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size).  Consider using the Jwts.SIG.HS256.key() builder (or HS384.key() or HS512.key()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm.  See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.

Utilisation

Émettre un jeton ES256 et l’analyser avec la clé, l’émetteur exigé et 30 secondes de tolérance de décalage d’horloge.
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.security.KeyPair;
import java.util.Date;

public class Usage {
    public static void main(String[] args) {
        KeyPair pair = Jwts.SIG.ES256.keyPair().build();
        String token = Jwts.builder()
            .subject("user-42")
            .issuer("https://auth.example.com")
            .expiration(new Date(System.currentTimeMillis() + 600_000))
            .signWith(pair.getPrivate(), Jwts.SIG.ES256)
            .compact();

        // The key decides which algorithms are acceptable; require iss and exp explicitly
        // and allow some clock skew (the default is none).
        Claims claims = Jwts.parser()
            .verifyWith(pair.getPublic())
            .requireIssuer("https://auth.example.com")
            .clockSkewSeconds(30)
            .build()
            .parseSignedClaims(token)
            .getPayload();
        System.out.println("sub: " + claims.getSubject() + ", has exp: " + (claims.getExpiration() != null));
    }
}

Le banc de test des extraits de code exécute chaque exemple tel quel dans l’image de conteneur maven:3.9.16-eclipse-temurin-25, et l’exécution échoue si la sortie ne correspond pas.

Mise en place
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Commande
java -cp 'lib/*' Usage.java
La sortie doit correspondre à cette expression régulière
sub: user-42, has exp: true

Bibliothèques