Zum Inhalt springen
ecdsa.com
Java · Kotlin

java-jwt (Auth0)

java-jwt von Auth0: eine kompakte JWT-Bibliothek, in der jeder Verifizierer an ein Objekt Algorithm gebunden ist, JWT.decode() nichts prüft und der Algorithmenumfang bei HS, RS und ES endet – kein PS256 und kein EdDSA.
Lizenz
MIT
Geprüfte Version
4.6.2 ·
Quellcode
github.com/auth0/java-jwt
Dokumentation
github.com/auth0/java-jwt#readme

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512ES256ES384ES512

java-jwt erzeugt Tokens mit JWT.create()…sign(algorithm) und prüft sie mit JWT.require(algorithm)…build().verify(token). Das Objekt Algorithm trägt sowohl den Algorithmus als auch den Schlüssel, sodass ein Verifizierer immer nur diesen einen Algorithmus akzeptiert: Ein RS256-Token, ein unsigniertes Token und ein mit dem PEM-Text des EC-Schlüssels gefälschtes HS256-Token scheiterten an einem ES256-Verifizierer allesamt mit AlgorithmMismatchException.

Dieser Schutz greift nur, solange das Objekt Algorithm anhand der Konfiguration gewählt wird. JWT.require(Algorithm.none()) akzeptiert unsignierte Tokens, und mit Algorithm.HMAC256(pemBytes) bestand das gefälschte HS256-Token die Prüfung – Code, der das Objekt Algorithm anhand des Headers alg im Token auswählt oder Schlüssel als rohe Bytes lädt, bringt die Algorithm-Confusion-Fehler zurück, die die API sonst verhindert. JWT.decode() parst, ohne die Signatur oder irgendeinen Claim zu prüfen; die Methode gab ein Token zurück, das eine Stunde zuvor abgelaufen war.

Die verfügbaren Algorithmen sind HMAC256/384/512, RSA256/384/512 und ECDSA256/384/512 – kein PS256, kein ES256K und kein EdDSA –, sodass Tokens von Ausstellern, die auf RSA-PSS oder Ed25519 umgestiegen sind, Nimbus oder JJWT brauchen. ES256 lehnt einen P-384-Schlüssel schon beim Signieren ab.

ES256-Signaturen sind das 64 Byte lange rohe r‖s, und eine DER-Signatur scheitert mit der allgemeinen Meldung The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA; der JWT-Debugger zeigt die Länge der Signatur. Standardmäßig gibt es keine Toleranz (Leeway), und exp ist optional: Das Beispiel ergänzt neben der Prüfung des Ausstellers withClaimPresence("exp") und acceptLeeway(30).

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/java-jwt/run.sh hat java-jwt (Auth0) 4.6.2 am 20. Oktober 2026 im Container-Image maven:3.9.16-eclipse-temurin-25 ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • JWS-Algorithmen

    HS256HS384HS512RS256RS384RS512ES256ES384ES512

    Signieren und Prüfen funktionierten mit HS, RS und ES bei 256/384/512; die Factory Algorithm bietet kein PS*, ES256K oder EdDSA.

    Von der Prüfung aufgezeichnet
    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
  • Kodierung von ES256-Signaturen

    raw

    ES256-Signaturen bestehen aus 64 Byte rohem r‖s.

    Von der Prüfung aufgezeichnet
    fact jws-ecdsa-encoding = raw
  • DER-Signatur in einer JWS

    rejected

    Eine DER-kodierte ES256-Signatur scheitert mit SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA
  • Allowlist der Algorithmen

    required

    Ein Verifizierer ist an ein einziges Objekt Algorithm gebunden: Ein RS256-Token scheiterte an JWT.require(ECDSA256) mit AlgorithmMismatchException.

    Von der Prüfung aufgezeichnet
    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.
  • Unsignierte Tokens (alg none)

    opt-in

    Ein ES256-Verifizierer lehnt unsignierte Tokens ab; JWT.require(Algorithm.none()) akzeptiert sie.

    Von der Prüfung aufgezeichnet
    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
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein HS256-Token mit dem PEM-Text als Schlüssel scheiterte am ES256-Verifizierer, mit Algorithm.HMAC256(pemBytes) bestand es dagegen die Prüfung.

    Von der Prüfung aufgezeichnet
    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
  • Abgleich der Kurve mit alg

    enforced

    Algorithm.ECDSA256 mit einem P-384-Schlüssel scheitert beim Signieren mit SignatureGenerationException.

    Von der Prüfung aufgezeichnet
    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
  • Standardtoleranz für Uhrabweichungen

    0s

    Standardmäßig keine Toleranz (Leeway): Ein Token, das drei Sekunden zuvor abgelaufen war, wurde abgelehnt.

    Von der Prüfung aufgezeichnet
    fact jwt-clock-skew = 0s
  • Ablauf-Claim erforderlich

    no

    Ein Token ohne exp bestand die Prüfung; withClaimPresence("exp") macht den Claim zur Pflicht.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no

Verwendung

Signiere ein ES256-Token und prüfe es mit festgelegtem Aussteller, verpflichtendem exp und 30 Sekunden Toleranz.
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());
    }
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image maven:3.9.16-eclipse-temurin-25 aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Befehl
java -cp 'lib/*' Usage.java
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken