Pular para o conteúdo
ecdsa.com
Rust

jsonwebtoken (Rust)

O crate jsonwebtoken, de Vincent Prouillet, a biblioteca JWT mais usada em Rust: um enum Algorithm fechado e sem none, exp obrigatória, 60 segundos de tolerância padrão e — desde a versão 10 — um backend criptográfico que você precisa escolher.
Licença
MIT
Versão verificada
11.1.0 ·
Código-fonte
github.com/Keats/jsonwebtoken
Documentação
docs.rs/jsonwebtoken/11.1.0/jsonwebtoken/

Visão geral da compatibilidade

JOSE e JWT

Algoritmos JWS
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

O jsonwebtoken codifica e decodifica JWTs com encode, decode e um objeto Validation, usando o serde para as claims. Desde a versão 10, a criptografia vem de um backend escolhido por feature flag — aws_lc_rs ou rust_crypto —, e o teste usou aws_lc_rs. Esquecer a feature não quebra o build: só com as features padrão, a versão 11.1.0 compilou e depois entrou em pânico no primeiro encode() com Could not automatically determine the process-level CryptoProvider. Ative exatamente um backend, como faz o manifesto do exemplo.

O conjunto de algoritmos é um enum fechado: HS, RS e PS em 256/384/512, ES256, ES384 e EdDSA funcionaram tanto na assinatura quanto na verificação, enquanto ES512, ES256K e Ed25519 nem sequer são variantes. Também não há variante none; por isso, um token sem assinatura já falha na análise do cabeçalho, com unknown variant none. Validation::new(alg) é a lista de algoritmos permitidos: um token HS256 verificado com Validation::new(ES256) falhou com InvalidAlgorithm e, mesmo com os dois algoritmos permitidos, um token HS256 que usava como chave o texto PEM da chave pública EC falhou com InvalidKeyFormat, porque uma DecodingKey EC não pode servir de segredo HMAC.

A validação das claims é mais rígida do que na maioria das bibliotecas: um token sem exp falha com Missing required claim: exp, e a tolerância padrão é de 60 segundos — um token que tinha expirado 57 segundos antes ainda foi considerado válido. Reduza leeway e defina o emissor e o público-alvo na Validation, como faz o exemplo. O ES256 recusa uma chave P-384 no momento da assinatura com InvalidEcdsaKey.

As assinaturas ES256 são o r‖s bruto de 64 bytes que o JWS exige, e uma assinatura DER falha com InvalidSignature. As chaves são carregadas de PEM (from_ec_pem, from_rsa_pem, from_ed_pem) e de DER; no caso do Ed25519 em DER, a chave de codificação recebeu PKCS#8 e a chave de decodificação, a chave pública bruta de 32 bytes. Inspecione tokens com o depurador de JWT e teste segredos HMAC com o verificador de segredos JWT.

Para assinaturas fora do JWT, use diretamente os crates de backend: aws-lc-rs ou RustCrypto ecdsa.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/jsonwebtoken-rust/run.sh executou jsonwebtoken (Rust) 11.1.0 na imagem de contêiner rust:1.99.1-trixie em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Algoritmos JWS

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

    Assinatura e verificação funcionaram com HS, RS e PS em 256/384/512, ES256, ES384 e EdDSA; ES512, ES256K e Ed25519 não são variantes de Algorithm.

    Registrado pela verificação
    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
  • Codificação da assinatura ES256

    raw

    As assinaturas ES256 são 64 bytes de r‖s brutos.

    Registrado pela verificação
    fact jws-ecdsa-encoding = raw
  • Assinatura DER dentro de um JWS

    rejected

    Uma assinatura ES256 codificada em DER falha com InvalidSignature.

    Registrado pela verificação
    fact jws-der-signature = rejected
    evidence jws-der-signature: Err("InvalidSignature")
  • Lista de algoritmos permitidos

    required

    Validation::new(alg) define os algoritmos permitidos; um token HS256 verificado com Validation::new(ES256) falhou com InvalidAlgorithm.

    Registrado pela verificação
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: HS256 token with Validation::new(ES256): Err("InvalidAlgorithm")
  • Tokens sem assinatura (alg none)

    rejected

    none não é uma variante de Algorithm: a análise do cabeçalho falha com unknown variant none.

    Registrado pela verificação
    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
  • Chave pública usada como segredo HMAC

    rejected

    Com ES256 e HS256 permitidos, um token HS256 que usava o texto PEM como chave falhou contra a DecodingKey EC com InvalidKeyFormat.

    Registrado pela verificação
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: algorithms [ES256, HS256], EC DecodingKey: Err("InvalidKeyFormat")
  • Curva conferida com o alg

    enforced

    Assinar ES256 com uma chave P-384 falha com InvalidEcdsaKey.

    Registrado pela verificação
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: Ok(Err("InvalidEcdsaKey"))
  • Tolerância padrão de diferença de relógio

    60s

    Validation::new define leeway como 60 segundos: um token expirado 57 segundos antes foi considerado válido; um expirado 63 segundos antes, não.

    Registrado pela verificação
    fact jwt-clock-skew = 60s
    evidence jwt-clock-skew: Validation::new(HS256).leeway = 60
  • Claim de expiração obrigatória

    yes

    Um token sem exp falha com Missing required claim: exp.

    Registrado pela verificação
    fact jwt-exp-required = yes
    evidence jwt-exp-required: Err("Missing required claim: exp")
  • Nenhum backend criptográfico selecionado

    runtime-panic

    Sem aws_lc_rs nem rust_crypto ativados, o crate compilou, e o primeiro encode() entrou em pânico com Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

    Registrado pela verificação
    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.

Uso

Emita um token HS256 e valide-o com o algoritmo, o emissor e uma tolerância de 30 segundos definidos explicitamente.
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);
}

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner rust:1.99.1-trixie, e a execução falha se a saída não corresponder.

Comando
cargo run --quiet --release
A saída deve corresponder a (expressão regular)
sub: user-42

Bibliotecas