Zum Inhalt springen
ecdsa.com
Rust

jsonwebtoken (Rust)

Das Crate jsonwebtoken von Vincent Prouillet, die meistgenutzte JWT-Bibliothek für Rust: ein geschlossenes Enum Algorithm ohne none, verpflichtendes exp, standardmäßig 60 Sekunden Toleranz (Leeway) und – seit Version 10 – ein Krypto-Backend, das du selbst auswählen musst.
Lizenz
MIT
Geprüfte Version
11.1.0 ·
Quellcode
github.com/Keats/jsonwebtoken
Dokumentation
docs.rs/jsonwebtoken/11.1.0/jsonwebtoken/

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

jsonwebtoken kodiert und dekodiert JWTs mit encode, decode und einem Objekt Validation und nutzt serde für die Claims. Seit Version 10 stammt die Kryptografie aus einem Backend, das per Feature-Flag ausgewählt wird (aws_lc_rs oder rust_crypto); für die Prüfung wurde aws_lc_rs verwendet. Ein vergessenes Feature lässt den Build nicht scheitern: Nur mit den Standard-Features ließ sich Version 11.1.0 kompilieren, löste dann aber beim ersten encode() eine Panic mit Could not automatically determine the process-level CryptoProvider aus. Aktiviere genau ein Backend, wie es das Manifest des Beispiels tut.

Die Algorithmen bilden ein geschlossenes Enum: Mit HS, RS und PS bei 256/384/512, ES256, ES384 und EdDSA funktionierten Signieren und Prüfen, während ES512, ES256K und Ed25519 gar keine Varianten sind. Auch eine Variante none gibt es nicht, ein unsigniertes Token scheitert also schon beim Parsen seines Headers mit unknown variant none. Validation::new(alg) ist die Liste der zulässigen Algorithmen: Ein HS256-Token, geprüft mit Validation::new(ES256), scheiterte mit InvalidAlgorithm, und selbst mit beiden zugelassenen Algorithmen scheiterte ein HS256-Token, dessen HMAC-Schlüssel der PEM-Text des öffentlichen Schlüssels vom Typ EC ist, mit InvalidKeyFormat, weil ein DecodingKey vom Typ EC nicht als HMAC-Secret dienen kann.

Die Prüfung der Claims ist strenger als in den meisten Bibliotheken: Ein Token ohne exp scheitert mit Missing required claim: exp, und die Standardtoleranz beträgt 60 Sekunden – ein Token, das 57 Sekunden zuvor abgelaufen war, galt noch als gültig. Verringere leeway und setze Aussteller und Audience im Objekt Validation, wie es das Beispiel tut. ES256 lehnt einen P-384-Schlüssel schon beim Signieren mit InvalidEcdsaKey ab.

ES256-Signaturen sind das 64 Byte lange rohe r‖s, das JWS verlangt, und eine DER-Signatur scheitert mit InvalidSignature. Schlüssel lassen sich aus PEM (from_ec_pem, from_rsa_pem, from_ed_pem) und DER laden; bei Ed25519 in DER nahm der Schlüssel zum Kodieren PKCS#8 entgegen und der Schlüssel zum Dekodieren den rohen, 32 Byte langen öffentlichen Schlüssel. Untersuche Tokens im JWT-Debugger und teste HMAC-Secrets mit dem JWT-Secret-Checker.

Für Signaturen außerhalb von JWT nutze die Backend-Crates direkt: aws-lc-rs oder RustCrypto ecdsa.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/jsonwebtoken-rust/run.sh hat jsonwebtoken (Rust) 11.1.0 am 20. Oktober 2026 im Container-Image rust:1.99.1-trixie ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • JWS-Algorithmen

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

    Signieren und Prüfen funktionierten mit HS, RS und PS bei 256/384/512 sowie mit ES256, ES384 und EdDSA; ES512, ES256K und Ed25519 sind keine Varianten von Algorithm.

    Von der Prüfung aufgezeichnet
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, EdDSA
    evidence jws-algorithms: ES512: not an Algorithm variant
    evidence jws-algorithms: ES256K: not an Algorithm variant
    evidence jws-algorithms: Ed25519: not an Algorithm variant
  • 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 InvalidSignature.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: Err("InvalidSignature")
  • Allowlist der Algorithmen

    required

    Validation::new(alg) legt die zulässigen Algorithmen fest; ein HS256-Token, geprüft mit Validation::new(ES256), scheiterte mit InvalidAlgorithm.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: HS256 token with Validation::new(ES256): Err("InvalidAlgorithm")
  • Unsignierte Tokens (alg none)

    rejected

    none ist keine Variante von Algorithm: Das Parsen des Headers scheitert mit unknown variant none.

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: Err("JSON error: unknown variant `none`, expected one of `HS256`, `HS384`, `HS512`, `ES256`, `ES384`, `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `EdDSA` at line 1 column 13"); "none" parses as Algorithm: false
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Mit ES256 und HS256 als zulässigen Algorithmen scheiterte ein HS256-Token mit dem PEM-Text als Schlüssel am DecodingKey vom Typ EC mit InvalidKeyFormat.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: algorithms [ES256, HS256], EC DecodingKey: Err("InvalidKeyFormat")
  • Abgleich der Kurve mit alg

    enforced

    Das Signieren mit ES256 und einem P-384-Schlüssel scheitert mit InvalidEcdsaKey.

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: Ok(Err("InvalidEcdsaKey"))
  • Standardtoleranz für Uhrabweichungen

    60s

    Validation::new setzt leeway auf 60 Sekunden: Ein Token, das 57 Sekunden zuvor abgelaufen war, galt als gültig, eines, das 63 Sekunden zuvor abgelaufen war, nicht.

    Von der Prüfung aufgezeichnet
    fact jwt-clock-skew = 60s
    evidence jwt-clock-skew: Validation::new(HS256).leeway = 60
  • Ablauf-Claim erforderlich

    yes

    Ein Token ohne exp scheitert mit Missing required claim: exp.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = yes
    evidence jwt-exp-required: Err("Missing required claim: exp")
  • Kein Kryptografie-Backend ausgewählt

    runtime-panic

    War weder aws_lc_rs noch rust_crypto aktiviert, kompilierte das Crate, und das erste encode() löste eine Panic aus: Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

    Von der Prüfung aufgezeichnet
    fact crypto-provider-without-feature = runtime-panic
    evidence crypto-provider-without-feature: default features compile; the first encode() panics with: Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

Verwendung

Stelle ein HS256-Token aus und validiere es mit ausdrücklich gesetztem Algorithmus und Aussteller sowie einer Toleranz von 30 Sekunden.
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Serialize, Deserialize)]
struct Claims {
    sub: String,
    iss: String,
    exp: u64,
}

fn main() {
    // Choose a backend explicitly: features = ["aws_lc_rs"] or ["rust_crypto"].
    let secret = b"use at least 32 random bytes from a secrets manager";
    let exp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 600;
    let claims = Claims { sub: "user-42".into(), iss: "https://auth.example.com".into(), exp };
    let token = encode(&Header::new(Algorithm::HS256), &claims, &EncodingKey::from_secret(secret)).unwrap();

    // Validation::new(alg) is the allow-list; exp is required, leeway defaults to 60 s.
    let mut validation = Validation::new(Algorithm::HS256);
    validation.set_issuer(&["https://auth.example.com"]);
    validation.leeway = 30;
    let data = decode::<Claims>(&token, &DecodingKey::from_secret(secret), &validation).unwrap();
    println!("sub: {}", data.claims.sub);
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image rust:1.99.1-trixie aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Befehl
cargo run --quiet --release
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken