Перейти к содержимому
ecdsa.com
Rust

jsonwebtoken (Rust)

Крейт jsonwebtoken Венсана Пруйе — самая используемая библиотека JWT для Rust: закрытое перечисление Algorithm без none, обязательный exp, допуск на расхождение часов 60 секунд по умолчанию и — начиная с версии 10 — криптографический бэкенд, который нужно выбрать самостоятельно.
Лицензия
MIT
Проверенная версия
11.1.0 ·
Исходный код
github.com/Keats/jsonwebtoken
Документация
docs.rs/jsonwebtoken/11.1.0/jsonwebtoken/

Совместимость вкратце

JOSE и JWT

Алгоритмы JWS
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

jsonwebtoken кодирует и декодирует JWT с помощью encode, decode и объекта Validation, а утверждения обрабатывает через serde. Начиная с версии 10 криптографию предоставляет бэкенд, который выбирается feature-флагом (aws_lc_rs или rust_crypto); при проверке использовался aws_lc_rs. Если забыть включить feature-флаг, сборка не завершится ошибкой: только с feature-флагами по умолчанию версия 11.1.0 скомпилировалась, а затем при первом вызове encode() завершилась паникой Could not automatically determine the process-level CryptoProvider. Включите ровно один бэкенд, как это сделано в манифесте примера.

Набор алгоритмов — закрытое перечисление: для HS, RS и PS на 256/384/512, ES256, ES384 и EdDSA подпись и проверка прошли успешно, а ES512, ES256K и Ed25519 вообще не входят в число вариантов. Варианта none тоже нет, поэтому неподписанный токен не проходит уже разбор заголовка: возникает ошибка unknown variant none. Список разрешённых алгоритмов задаёт Validation::new(alg): проверка токена HS256 с Validation::new(ES256) завершилась ошибкой InvalidAlgorithm, и даже когда разрешены оба алгоритма, токен HS256, подписанный текстом PEM открытого ключа EC, не прошёл проверку с ошибкой InvalidKeyFormat, потому что DecodingKey для EC не может служить секретом HMAC.

Утверждения проверяются строже, чем в большинстве библиотек: токен без exp не проходит проверку с ошибкой Missing required claim: exp, а допуск на расхождение часов по умолчанию равен 60 секундам — токен, срок действия которого истёк 57 секунд назад, всё ещё прошёл проверку. Уменьшите leeway и задайте издателя и аудиторию в Validation, как это делает пример. ES256 не принимает ключ P-384 уже при подписи и выдаёт InvalidEcdsaKey.

Подписи ES256 — это 64-байтовый формат raw r‖s, которого требует JWS, а подпись DER не проходит проверку с ошибкой InvalidSignature. Ключи загружаются из PEM (from_ec_pem, from_rsa_pem, from_ed_pem) и DER; для Ed25519 в формате DER ключ кодирования принял PKCS#8, а ключ декодирования — 32-байтовый открытый ключ в формате raw. Разбирайте токены в отладчике JWT, а секреты HMAC проверяйте инструментом проверки секретов JWT.

Для подписей вне JWT используйте крейты бэкендов напрямую: aws-lc-rs или RustCrypto ecdsa.

Факты и проверки, на которых они основаны

Ничего из приведённого ниже не скопировано из документации. 20 октября 2026 г. проверка content/libraries/verify/jsonwebtoken-rust/run.sh запустила jsonwebtoken (Rust) 11.1.0 в образе контейнера rust:1.99.1-trixie; содержимое страницы должно совпадать с выводом проверки, а у каждого факта приведены соответствующие строки вывода.

  • Алгоритмы JWS

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

    Подпись и проверка работают для HS, RS и PS на 256/384/512, ES256, ES384 и EdDSA; ES512, ES256K и Ed25519 не входят в варианты Algorithm.

    Что записала проверка
    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
  • Кодировка подписи ES256

    raw

    Подписи ES256 — 64 байта в формате raw r‖s.

    Что записала проверка
    fact jws-ecdsa-encoding = raw
  • Подпись в DER внутри JWS

    rejected

    Подпись ES256 в кодировке DER не проходит проверку с ошибкой InvalidSignature.

    Что записала проверка
    fact jws-der-signature = rejected
    evidence jws-der-signature: Err("InvalidSignature")
  • Список разрешённых алгоритмов

    required

    Validation::new(alg) задаёт разрешённые алгоритмы; проверка токена HS256 с Validation::new(ES256) завершилась ошибкой InvalidAlgorithm.

    Что записала проверка
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: HS256 token with Validation::new(ES256): Err("InvalidAlgorithm")
  • Неподписанные токены (alg none)

    rejected

    none не входит в варианты Algorithm: разбор заголовка завершается ошибкой unknown variant none.

    Что записала проверка
    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
  • Открытый ключ в роли секрета HMAC

    rejected

    Когда разрешены и ES256, и HS256, токен HS256, подписанный текстом PEM в качестве ключа, не прошёл проверку с DecodingKey для EC: возникла ошибка InvalidKeyFormat.

    Что записала проверка
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: algorithms [ES256, HS256], EC DecodingKey: Err("InvalidKeyFormat")
  • Сверка кривой с alg

    enforced

    При подписи ES256 ключом P-384 возникает ошибка InvalidEcdsaKey.

    Что записала проверка
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: Ok(Err("InvalidEcdsaKey"))
  • Допустимое расхождение часов по умолчанию

    60s

    Validation::new устанавливает leeway равным 60 секундам: токен, срок действия которого истёк 57 секунд назад, прошёл проверку, а просроченный на 63 секунды — нет.

    Что записала проверка
    fact jwt-clock-skew = 60s
    evidence jwt-clock-skew: Validation::new(HS256).leeway = 60
  • Обязательное утверждение о сроке действия

    yes

    Токен без exp не проходит проверку с ошибкой Missing required claim: exp.

    Что записала проверка
    fact jwt-exp-required = yes
    evidence jwt-exp-required: Err("Missing required claim: exp")
  • Криптографический бэкенд не выбран

    runtime-panic

    Когда не включён ни aws_lc_rs, ни rust_crypto, крейт скомпилировался, а первый вызов encode() завершился паникой Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

    Что записала проверка
    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.

Использование

Выпустите токен HS256 и проверьте его, явно задав алгоритм, издателя и допуск на расхождение часов в 30 секунд.
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);
}

Тестовый стенд для фрагментов кода запускает каждый пример без изменений в образе контейнера rust:1.99.1-trixie, и запуск завершается ошибкой, если вывод не совпадает.

Команда
cargo run --quiet --release
Вывод должен совпадать (регулярное выражение)
sub: user-42

Библиотеки