Zum Inhalt springen
ecdsa.com
Java · Kotlin

Nimbus JOSE + JWT

Nimbus JOSE + JWT von Connect2id, die JOSE-Bibliothek in Spring Security und vielen OAuth-Servern für Java: ein Prozessor, dessen Schlüsselselektor die Allowlist der Algorithmen ist, Ablehnung unsignierter Tokens und standardmäßig 60 Sekunden Toleranz für Uhrenabweichungen.
Lizenz
Apache-2.0
Geprüfte Version
10.10 ·
Quellcode
bitbucket.org/connect2id/nimbus-jose-jwt
Dokumentation
connect2id.com/products/nimbus-jose-jwt

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSAEd25519

Nimbus deckt JWS, JWE, JWK und JWT mit zwei Schichten ab: Low-Level-Objekte (SignedJWT, ECDSASigner, MACVerifier) und den DefaultJWTProcessor, der Schlüsselauswahl, Signaturprüfung und Prüfung der Claims zusammenführt. Der Ressourcenserver von Spring Security baut darauf auf, deshalb setzen die meisten Spring-APIs genau diese Standardeinstellungen durch.

Mit dem Prozessor ist der JWSVerificationKeySelector die Allowlist: Für ES256 konfiguriert, lehnte er ein RS256-Token und ein HS256-Token mit dem PEM-Text des EC-Schlüssels als Schlüssel mit Another algorithm expected, or no matching key(s) found ab, und ganz ohne Selektor lehnt der Prozessor alles ab. Unsignierte Tokens werden abgelehnt (Unsecured (plain) JWTs are rejected, extend class to handle). Die Low-Level-API hat keinen solchen Schutz – ein aus dem PEM-Text gebauter MACVerifier akzeptierte das gefälschte HS256-Token –, deshalb baut Code, der einen Verifizierer anhand des Headers des Tokens auswählt, den klassischen Algorithm-Confusion-Fehler nach. Verwende den Prozessor, wie es das Beispiel tut.

DefaultJWTClaimsVerifier lässt standardmäßig 60 Sekunden Uhrenabweichung zu, und exp ist optional, sofern der Claim nicht als Pflicht-Claim aufgeführt ist – das Beispiel verlangt sub und exp und legt den Aussteller fest. ES256 lehnt einen P-384-Schlüssel ab (The ES256 algorithm is not allowed or supported by the JWS signer), und eine DER-kodierte Signatur besteht die Prüfung einfach nicht; prüfe die Länge der Signatur mit dem JWT-Debugger.

Version 10.10 bestand den Roundtrip mit den Familien HS, RS, PS und ES sowie mit EdDSA und dem neueren Namen Ed25519. Ed25519 braucht Google Tink im Classpath: Ohne Tink scheiterte das Signieren mit NoClassDefFoundError: com/google/crypto/tink/subtle/Ed25519Sign$KeyPair. ES256K braucht einen Provider mit secp256k1 wie Bouncy Castle, da das JDK keinen mitbringt.

Was ein Identity Provider veröffentlicht, prüfst du mit dem JWKS-Checker; bei verschlüsselten Tokens hilft der JWE-Inspektor.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/nimbus-jose-jwt/run.sh hat Nimbus JOSE + JWT 10.10 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

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSAEd25519

    Signieren und Prüfen funktionierten auf dem JDK mit HS, RS, PS und ES bei 256/384/512 sowie mit EdDSA und Ed25519; ES256K und Ed448 bestanden den Roundtrip mit den Providern des JDK nicht.

    Von der Prüfung aufgezeichnet
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA, Ed25519
    evidence jws-algorithms: ES256K: not round-tripped with the JDK providers
    evidence jws-algorithms: Ed448: not round-tripped with the JDK providers
  • 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

    Ein Token mit einer DER-kodierten ES256-Signatur bestand die Prüfung nicht.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: not verified
  • Allowlist der Algorithmen

    required

    DefaultJWTProcessor braucht einen Schlüsselselektor: Ohne ihn scheitert er mit No JWS key selector is configured, und ein Selektor für ES256 lehnte ein RS256-Token ab.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: DefaultJWTProcessor with a JWSVerificationKeySelector for ES256, RS256 token: BadJOSEException: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
    evidence jwt-algorithm-allowlist: DefaultJWTProcessor without a key selector: BadJOSEException: Signed JWT rejected: No JWS key selector is configured
  • Unsignierte Tokens (alg none)

    rejected

    Der Prozessor lehnt unsignierte Tokens mit Unsecured (plain) JWTs are rejected, extend class to handle ab.

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: DefaultJWTProcessor: BadJOSEException: Unsecured (plain) JWTs are rejected, extend class to handle
    evidence jwt-alg-none: SignedJWT.parse: ParseException: Invalid JWS header: Not a JWS header
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein HS256-Token mit dem PEM-Text als Schlüssel wurde vom für ES256 konfigurierten Prozessor abgelehnt, ein von Hand aus diesem PEM-Text gebauter MACVerifier akzeptierte es dagegen.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: DefaultJWTProcessor with the ES256 key selector: BadJOSEException: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
    evidence jwt-hmac-public-key: a MACVerifier built from the PEM text by hand: verified
  • Abgleich der Kurve mit alg

    enforced

    Das Signieren mit ES256 und einem P-384-Schlüssel scheitert mit The ES256 algorithm is not allowed or supported by the JWS signer: Supported algorithms: [ES384].

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: JOSEException: The ES256 algorithm is not allowed or supported by the JWS signer: Supported algorithms: [ES384]
  • Standardtoleranz für Uhrabweichungen

    60s

    DefaultJWTClaimsVerifier lässt 60 Sekunden zu (DEFAULT_MAX_CLOCK_SKEW_SECONDS).

    Von der Prüfung aufgezeichnet
    fact jwt-clock-skew = 60s
    evidence jwt-clock-skew: DefaultJWTClaimsVerifier.DEFAULT_MAX_CLOCK_SKEW_SECONDS = 60
  • Ablauf-Claim erforderlich

    no

    Ein Token ohne exp bestand die Standardprüfung der Claims; wird exp als Pflicht-Claim aufgeführt, scheitert es mit JWT missing required claims: [exp].

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no
    evidence jwt-exp-required: with DefaultJWTClaimsVerifier requiring exp: BadJWTException: JWT missing required claims: [exp]
  • Ed25519 ohne Google Tink

    fails

    Ohne Google Tink im Classpath scheiterte das Signieren mit Ed25519Signer mit NoClassDefFoundError: com/google/crypto/tink/subtle/Ed25519Sign$KeyPair.

    Von der Prüfung aufgezeichnet
    fact ed25519-without-tink = fails
    evidence ed25519-without-tink: NoClassDefFoundError: com/google/crypto/tink/subtle/Ed25519Sign$KeyPair

Verwendung

Signiere ein ES256-Token mit einer Schlüssel-ID und verarbeite es mit einem Schlüsselselektor nur für ES256 und einem Claims-Verifizierer, der sub, exp und den Aussteller verlangt.
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.proc.*;
import com.nimbusds.jwt.*;
import com.nimbusds.jwt.proc.*;
import java.util.*;

public class Usage {
    public static void main(String[] args) throws Exception {
        ECKey key = new ECKeyGenerator(Curve.P_256).keyID("2026-10").generate();
        JWTClaimsSet claims = new JWTClaimsSet.Builder().subject("user-42").issuer("https://auth.example.com")
            .expirationTime(new Date(System.currentTimeMillis() + 600_000)).build();
        SignedJWT jwt = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.ES256).keyID(key.getKeyID()).build(), claims);
        jwt.sign(new ECDSASigner(key));

        // The key selector is the algorithm allow-list; the claims verifier requires iss and exp.
        DefaultJWTProcessor<SecurityContext> processor = new DefaultJWTProcessor<>();
        processor.setJWSKeySelector(new JWSVerificationKeySelector<>(JWSAlgorithm.ES256, new ImmutableJWKSet<>(new JWKSet(key.toPublicJWK()))));
        processor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>(
            new JWTClaimsSet.Builder().issuer("https://auth.example.com").build(), new HashSet<>(List.of("sub", "exp"))));
        System.out.println("sub: " + processor.process(jwt.serialize(), null).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 -Dartifact=com.nimbusds:nimbus-jose-jwt:10.10 -DoutputDirectory=lib >/dev/null
Befehl
java -cp lib/nimbus-jose-jwt-10.10.jar Usage.java
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken