Aller au contenu
ecdsa.com
Java · Kotlin

java-jwt (Auth0)

java-jwt d’Auth0 : une bibliothèque JWT compacte où chaque vérificateur est lié à un seul objet Algorithm, où JWT.decode() ne vérifie rien et dont le jeu d’algorithmes s’arrête à HS, RS et ES, sans PS256 ni EdDSA.
Licence
MIT
Version vérifiée
4.6.2 ·
Code source
github.com/auth0/java-jwt
Documentation
github.com/auth0/java-jwt#readme

Compatibilité en un coup d’œil

JOSE et JWT

Algorithmes JWS
HS256HS384HS512RS256RS384RS512ES256ES384ES512

java-jwt construit les jetons avec JWT.create()…sign(algorithm) et les vérifie avec JWT.require(algorithm)…build().verify(token). L’objet Algorithm porte à la fois l’algorithme et la clé, si bien qu’un vérificateur n’accepte jamais que cet unique algorithme : un jeton RS256, un jeton non signé et un jeton HS256 falsifié avec le texte PEM de la clé EC ont tous échoué face à un vérificateur ES256 avec AlgorithmMismatchException.

Cette protection ne tient que tant que l’Algorithm est choisi d’après la configuration. JWT.require(Algorithm.none()) accepte les jetons non signés, et Algorithm.HMAC256(pemBytes) a vérifié le jeton HS256 falsifié : un code qui choisit l’Algorithm d’après l’en-tête alg du jeton, ou qui charge les clés sous forme d’octets bruts, recrée les bugs de confusion d’algorithme que l’API empêche autrement. JWT.decode() analyse le jeton sans vérifier la signature ni aucun claim ; il a renvoyé un jeton expiré depuis une heure.

Le jeu d’algorithmes se compose de HMAC256/384/512, RSA256/384/512 et ECDSA256/384/512, sans PS256, ni ES256K, ni EdDSA : les jetons des émetteurs passés à RSA-PSS ou à Ed25519 exigent donc Nimbus ou JJWT. ES256 refuse une clé P-384 à la signature.

Les signatures ES256 sont au format r‖s brut de 64 octets, et une signature DER échoue avec le message générique The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA ; le débogueur JWT affiche la longueur de la signature. Il n’y a pas de marge de tolérance par défaut et exp est facultatif : l’exemple ajoute withClaimPresence("exp") et acceptLeeway(30) en plus du contrôle de l’émetteur.

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/java-jwt/run.sh a exécuté java-jwt (Auth0) 4.6.2 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

    HS256HS384HS512RS256RS384RS512ES256ES384ES512

    Signature et vérification réussies avec HS, RS et ES en 256/384/512 ; la fabrique Algorithm ne propose ni PS*, ni ES256K, ni EdDSA.

    Relevé par la vérification
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512
    evidence jws-algorithms: Algorithm factory methods: HMAC256/384/512, RSA256/384/512, ECDSA256/384/512, none; no PS*, ES256K or EdDSA
  • 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 SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA.

    Relevé par la vérification
    fact jws-der-signature = rejected
    evidence jws-der-signature: SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA
  • Liste d’algorithmes autorisés

    required

    Un vérificateur est lié à un seul Algorithm : un jeton RS256 présenté à JWT.require(ECDSA256) a échoué avec AlgorithmMismatchException.

    Relevé par la vérification
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: JWT.require(ECDSA256) on an RS256 token: AlgorithmMismatchException: The provided Algorithm doesn't match the one defined in the JWT's Header.
  • Jetons non signés (alg none)

    opt-in

    Un vérificateur ES256 rejette les jetons non signés ; JWT.require(Algorithm.none()) les accepte.

    Relevé par la vérification
    fact jwt-alg-none = opt-in
    evidence jwt-alg-none: JWT.require(ECDSA256): AlgorithmMismatchException: The provided Algorithm doesn't match the one defined in the JWT's Header.
    evidence jwt-alg-none: JWT.require(Algorithm.none()): verified
  • Clé publique utilisée comme secret HMAC

    rejected

    Un jeton HS256 dont la clé HMAC était le texte PEM a échoué face au vérificateur ES256, mais Algorithm.HMAC256(pemBytes) l’a vérifié.

    Relevé par la vérification
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: JWT.require(ECDSA256): AlgorithmMismatchException: The provided Algorithm doesn't match the one defined in the JWT's Header.
    evidence jwt-hmac-public-key: JWT.require(Algorithm.HMAC256(PEM bytes)): verified
  • Courbe vérifiée par rapport à alg

    enforced

    Algorithm.ECDSA256 avec une clé P-384 échoue à la signature avec SignatureGenerationException.

    Relevé par la vérification
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: SignatureGenerationException: The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA
  • Décalage d’horloge toléré par défaut

    0s

    Aucune marge de tolérance 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é vérifié ; withClaimPresence("exp") le rend obligatoire.

    Relevé par la vérification
    fact jwt-exp-required = no

Utilisation

Signer un jeton ES256 et le vérifier avec l’émetteur fixé, exp obligatoire et 30 secondes de tolérance.
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.time.Instant;

public class Usage {
    public static void main(String[] args) throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
        generator.initialize(new ECGenParameterSpec("secp256r1"));
        KeyPair pair = generator.generateKeyPair();
        Algorithm es256 = Algorithm.ECDSA256((ECPublicKey) pair.getPublic(), (ECPrivateKey) pair.getPrivate());

        String token = JWT.create().withSubject("user-42").withIssuer("https://auth.example.com")
            .withExpiresAt(Instant.now().plusSeconds(600)).sign(es256);

        // JWT.require() verifies; JWT.decode() only parses. Require exp and allow some leeway.
        DecodedJWT verified = JWT.require(es256).withIssuer("https://auth.example.com")
            .withClaimPresence("exp").acceptLeeway(30).build().verify(token);
        System.out.println("sub: " + verified.getSubject());
    }
}

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

Bibliothèques