Saltar al contenido
ecdsa.com
Java · Kotlin

java-jwt (Auth0)

java-jwt de Auth0: una biblioteca JWT compacta en la que cada verificador está ligado a un único objeto Algorithm, JWT.decode() no comprueba nada y los algoritmos se limitan a HS, RS y ES: ni PS256 ni EdDSA.
Licencia
MIT
Versión comprobada
4.6.2 ·
Código fuente
github.com/auth0/java-jwt
Documentación
github.com/auth0/java-jwt#readme

Compatibilidad de un vistazo

JOSE y JWT

Algoritmos JWS
HS256HS384HS512RS256RS384RS512ES256ES384ES512

java-jwt construye los tokens con JWT.create()…sign(algorithm) y los verifica con JWT.require(algorithm)…build().verify(token). El objeto Algorithm lleva tanto el algoritmo como la clave, así que un verificador solo acepta ese algoritmo: un token RS256, un token sin firmar y un token HS256 falsificado con el texto PEM de la clave EC fallaron todos contra un verificador ES256 con AlgorithmMismatchException.

La protección solo se mantiene mientras el Algorithm se elija a partir de la configuración. JWT.require(Algorithm.none()) acepta tokens sin firmar, y Algorithm.HMAC256(pemBytes) verificó el token HS256 falsificado: el código que elige el Algorithm según el encabezado alg del token, o que carga las claves como bytes sin más, reproduce los fallos de confusión de algoritmos que la API evita en otro caso. JWT.decode() analiza sin comprobar la firma ni ningún claim; devolvió un token que había caducado una hora antes.

El conjunto de algoritmos es HMAC256/384/512, RSA256/384/512 y ECDSA256/384/512 —sin PS256, sin ES256K y sin EdDSA—, así que los tokens de emisores que ya usan RSA-PSS o Ed25519 necesitan Nimbus o JJWT. ES256 rechaza una clave P-384 al firmar.

Las firmas ES256 son el r‖s en bruto de 64 bytes, y una firma DER falla con el genérico The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA; el decodificador de JWT muestra la longitud de la firma. No hay tolerancia predeterminada y exp es opcional: el ejemplo añade withClaimPresence("exp") y acceptLeeway(30) junto con la comprobación del emisor.

Datos y las comprobaciones que los respaldan

Nada de lo que sigue está copiado de la documentación. La comprobación content/libraries/verify/java-jwt/run.sh ejecutó java-jwt (Auth0) 4.6.2 en la imagen de contenedor maven:3.9.16-eclipse-temurin-25 el 20 de octubre de 2026; la página debe coincidir con lo que imprimió, y cada dato cita esas líneas.

  • Algoritmos JWS

    HS256HS384HS512RS256RS384RS512ES256ES384ES512

    Con HS, RS y ES de 256/384/512 se firmó y se verificó; la fábrica Algorithm no tiene PS*, ES256K ni EdDSA.

    Registrado por la comprobación
    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
  • Codificación de la firma ES256

    raw

    Las firmas ES256 son 64 bytes de r‖s en bruto.

    Registrado por la comprobación
    fact jws-ecdsa-encoding = raw
  • Firma DER dentro de un JWS

    rejected

    Una firma ES256 codificada en DER falla con SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA.

    Registrado por la comprobación
    fact jws-der-signature = rejected
    evidence jws-der-signature: SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA
  • Lista de algoritmos permitidos

    required

    Un verificador está ligado a un único Algorithm: un token RS256 contra JWT.require(ECDSA256) falló con AlgorithmMismatchException.

    Registrado por la comprobación
    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.
  • Tokens sin firma (alg none)

    opt-in

    Un verificador ES256 rechaza los tokens sin firmar; JWT.require(Algorithm.none()) los acepta.

    Registrado por la comprobación
    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
  • Clave pública usada como secreto HMAC

    rejected

    Un token HS256 con el texto PEM como clave falló contra el verificador ES256, pero Algorithm.HMAC256(pemBytes) lo verificó.

    Registrado por la comprobación
    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
  • Curva cotejada con alg

    enforced

    Algorithm.ECDSA256 con una clave P-384 falla al firmar con SignatureGenerationException.

    Registrado por la comprobación
    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
  • Desfase de reloj predeterminado

    0s

    Sin tolerancia por defecto: se rechazó un token caducado 3 segundos antes.

    Registrado por la comprobación
    fact jwt-clock-skew = 0s
  • Claim de caducidad obligatorio

    no

    Un token sin exp se verificó; withClaimPresence("exp") lo exige.

    Registrado por la comprobación
    fact jwt-exp-required = no

Uso

Firma un token ES256 y verifícalo con el emisor fijado, exp obligatorio y 30 segundos de tolerancia.
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());
    }
}

El arnés de pruebas de fragmentos de código ejecuta cada ejemplo tal cual en la imagen de contenedor maven:3.9.16-eclipse-temurin-25, y la ejecución falla si la salida no coincide.

Configuración
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Comando
java -cp 'lib/*' Usage.java
La salida debe coincidir (expresión regular)
sub: user-42

Bibliotecas