Aller au contenu
ecdsa.com
Rust

jsonwebtoken (Rust)

La crate jsonwebtoken de Vincent Prouillet, la bibliothèque JWT la plus utilisée en Rust : une enum Algorithm fermée, sans none, un exp obligatoire, 60 secondes de marge de tolérance par défaut et, depuis la version 10, un backend cryptographique que vous devez choisir.
Licence
MIT
Version vérifiée
11.1.0 ·
Code source
github.com/Keats/jsonwebtoken
Documentation
docs.rs/jsonwebtoken/11.1.0/jsonwebtoken/

Compatibilité en un coup d’œil

JOSE et JWT

Algorithmes JWS
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

jsonwebtoken encode et décode des JWT avec encode, decode et un objet Validation, en s’appuyant sur serde pour les claims. Depuis la version 10, la cryptographie provient d’un backend choisi par une fonctionnalité Cargo (aws_lc_rs ou rust_crypto), et les essais ont utilisé aws_lc_rs. Oublier la fonctionnalité ne fait pas échouer le build : avec les seules fonctionnalités par défaut, la 11.1.0 a compilé, puis a paniqué au premier encode() avec Could not automatically determine the process-level CryptoProvider. Activez exactement un backend, comme le fait le manifeste de l’exemple.

L’ensemble des algorithmes est une enum fermée : la signature et la vérification ont réussi avec HS, RS et PS en 256/384/512, ES256, ES384 et EdDSA, tandis qu’ES512, ES256K et Ed25519 ne sont même pas des variantes. Il n’existe pas non plus de variante none, si bien qu’un jeton non signé échoue lors de l’analyse de son en-tête avec unknown variant none. Validation::new(alg) constitue la liste d’autorisation : un jeton HS256 contrôlé avec Validation::new(ES256) a échoué avec InvalidAlgorithm, et même avec les deux algorithmes autorisés, un jeton HS256 dont la clé est le texte PEM de la clé publique EC a échoué avec InvalidKeyFormat, car une DecodingKey EC ne peut pas servir de secret HMAC.

Les contrôles de claims sont plus stricts que dans la plupart des bibliothèques : un jeton sans exp échoue avec Missing required claim: exp, et la marge de tolérance par défaut est de 60 secondes (un jeton expiré depuis 57 secondes a encore été validé). Réduisez leeway et définissez l’émetteur et l’audience sur la Validation, comme le fait l’exemple. ES256 refuse une clé P-384 au moment de la signature avec InvalidEcdsaKey.

Les signatures ES256 sont le r‖s brut de 64 octets qu’exige JWS, et une signature DER échoue avec InvalidSignature. Les clés se chargent depuis du PEM (from_ec_pem, from_rsa_pem, from_ed_pem) et du DER ; pour Ed25519 en DER, la clé d’encodage a accepté du PKCS#8 et la clé de décodage la clé publique brute de 32 octets. Examinez les jetons avec le débogueur JWT et testez les secrets HMAC avec le vérificateur de secrets JWT.

Pour des signatures hors JWT, utilisez directement les crates des backends : aws-lc-rs ou RustCrypto ecdsa.

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/jsonwebtoken-rust/run.sh a exécuté jsonwebtoken (Rust) 11.1.0 dans l’image de conteneur rust:1.99.1-trixie 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

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

    Signature et vérification réussies avec HS, RS et PS en 256/384/512, ES256, ES384 et EdDSA ; ES512, ES256K et Ed25519 ne sont pas des variantes d’Algorithm.

    Relevé par la vérification
    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
  • 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 InvalidSignature.

    Relevé par la vérification
    fact jws-der-signature = rejected
    evidence jws-der-signature: Err("InvalidSignature")
  • Liste d’algorithmes autorisés

    required

    Validation::new(alg) définit les algorithmes autorisés ; un jeton HS256 contrôlé avec Validation::new(ES256) a échoué avec InvalidAlgorithm.

    Relevé par la vérification
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: HS256 token with Validation::new(ES256): Err("InvalidAlgorithm")
  • Jetons non signés (alg none)

    rejected

    none n’est pas une variante d’Algorithm : l’analyse de l’en-tête échoue avec unknown variant none.

    Relevé par la vérification
    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
  • Clé publique utilisée comme secret HMAC

    rejected

    Avec ES256 et HS256 tous deux autorisés, un jeton HS256 dont la clé est le texte PEM a échoué face à la DecodingKey EC avec InvalidKeyFormat.

    Relevé par la vérification
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: algorithms [ES256, HS256], EC DecodingKey: Err("InvalidKeyFormat")
  • Courbe vérifiée par rapport à alg

    enforced

    Signer en ES256 avec une clé P-384 échoue avec InvalidEcdsaKey.

    Relevé par la vérification
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: Ok(Err("InvalidEcdsaKey"))
  • Décalage d’horloge toléré par défaut

    60s

    Validation::new fixe leeway à 60 secondes : un jeton expiré depuis 57 secondes a été validé, un jeton expiré depuis 63 secondes ne l’a pas été.

    Relevé par la vérification
    fact jwt-clock-skew = 60s
    evidence jwt-clock-skew: Validation::new(HS256).leeway = 60
  • Claim d’expiration obligatoire

    yes

    Un jeton sans exp échoue avec Missing required claim: exp.

    Relevé par la vérification
    fact jwt-exp-required = yes
    evidence jwt-exp-required: Err("Missing required claim: exp")
  • Aucun backend cryptographique sélectionné

    runtime-panic

    Sans aws_lc_rs ni rust_crypto activé, la crate a compilé et le premier encode() a paniqué avec Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

    Relevé par la vérification
    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.

Utilisation

Émettre un jeton HS256 et le valider en fixant explicitement l’algorithme, l’émetteur et une marge de tolérance de 30 secondes.
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);
}

Le banc de test des extraits de code exécute chaque exemple tel quel dans l’image de conteneur rust:1.99.1-trixie, et l’exécution échoue si la sortie ne correspond pas.

Commande
cargo run --quiet --release
La sortie doit correspondre à cette expression régulière
sub: user-42

Bibliothèques