jsonwebtokens 1.2.0

A Json Web Token implementation for Rust
Documentation
use serde_json::json;
use serde_json::value::Value;

use jsonwebtokens as jwt;
use jwt::{Algorithm, AlgorithmID, TokenData, Verifier};

use crate::common::get_time;

const RSA_ALGORITHMS: &[AlgorithmID] = &[
    AlgorithmID::RS256,
    AlgorithmID::RS384,
    AlgorithmID::RS512,
    AlgorithmID::PS256,
    AlgorithmID::PS384,
    AlgorithmID::PS512,
];

#[test]
#[should_panic(expected = "AlgorithmMismatch")]
fn decode_token_wrong_algorithm() {
    let pubkey_pem = include_bytes!("public_rsa_key_pkcs1.pem");

    let alg = Algorithm::new_rsa_pem_verifier(AlgorithmID::RS256, pubkey_pem).unwrap();
    let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUifQ.I1BvFoHe94AFf09O6tDbcSB8-jp8w6xZqmyHIwPeSdY";
    let verifier = Verifier::create().build().unwrap();
    let _claims: Value = verifier.verify(token, &alg).unwrap();
}

#[test]
fn round_trip_sign_verification_pem_pkcs1() {
    let privkey_pem = include_bytes!("private_rsa_key_pkcs1.pem");
    let pubkey_pem = include_bytes!("public_rsa_key_pkcs1.pem");

    for &id in RSA_ALGORITHMS {
        let alg = Algorithm::new_rsa_pem_signer(id, privkey_pem).unwrap();
        let signature = alg.sign("hello world").unwrap();
        let alg = Algorithm::new_rsa_pem_verifier(id, pubkey_pem).unwrap();
        alg.verify(None, "hello world", signature).unwrap();
    }
}

#[test]
fn round_trip_sign_verification_certificate_pem() {
    let privkey_pem = include_bytes!("private_rsa_key_pkcs1.pem");
    let certificate = include_bytes!("certificate_rsa_pkcs1.crt");

    for &id in RSA_ALGORITHMS {
        let alg = Algorithm::new_rsa_pem_signer(id, privkey_pem).unwrap();
        let signature = alg.sign("hello world").unwrap();
        let alg = Algorithm::new_rsa_pem_verifier(id, certificate).unwrap();
        alg.verify(None, "hello world", signature).unwrap();
    }
}

#[test]
fn round_trip_sign_verification_pem_pkcs8() {
    let privkey_pem = include_bytes!("private_rsa_key_pkcs8.pem");
    let pubkey_pem = include_bytes!("public_rsa_key_pkcs8.pem");

    for &id in RSA_ALGORITHMS {
        let alg = Algorithm::new_rsa_pem_signer(id, privkey_pem).unwrap();
        let signature = alg.sign("hello world").unwrap();
        let alg = Algorithm::new_rsa_pem_verifier(id, pubkey_pem).unwrap();
        alg.verify(None, "hello world", signature).unwrap();
    }
}

#[test]
fn round_trip_claims() {
    let privkey_pem = include_bytes!("private_rsa_key_pkcs8.pem");
    let pubkey_pem = include_bytes!("public_rsa_key_pkcs8.pem");

    let my_claims = json!({
        "sub": "b@b.com",
        "company": "ACME",
        "exp": get_time() + 10000,
    });

    for &id in RSA_ALGORITHMS {
        let alg = Algorithm::new_rsa_pem_signer(id, privkey_pem).unwrap();

        let header = json!({"alg": alg.name(), "my_hdr": "my_hdr_val"});
        let token = jwt::encode(&header, &my_claims, &alg).unwrap();

        let alg = Algorithm::new_rsa_pem_verifier(id, pubkey_pem).unwrap();
        let verifier = Verifier::create().build().unwrap();
        let claims: Value = verifier.verify(token, &alg).unwrap();

        assert_eq!(my_claims, claims);
    }
}

#[test]
fn round_trip_claims_and_custom_header() {
    let privkey_pem = include_bytes!("private_rsa_key_pkcs1.pem");
    let pubkey_pem = include_bytes!("public_rsa_key_pkcs1.pem");

    let my_claims = json!({
        "sub": "b@b.com",
        "company": "ACME",
        "exp": get_time() + 10000,
    });

    for &id in RSA_ALGORITHMS {
        let alg = Algorithm::new_rsa_pem_signer(id, privkey_pem).unwrap();

        let header = json!({"alg": alg.name(), "kid": "kid1234", "my_hdr": "my_hdr_val"});
        let token = jwt::encode(&header, &my_claims, &alg).unwrap();

        let mut alg = Algorithm::new_rsa_pem_verifier(id, pubkey_pem).unwrap();
        alg.set_kid("kid1234");
        let verifier = Verifier::create().build().unwrap();

        // We have to use the lower-level for_time API if we want to see the header
        let TokenData { header, claims, .. } =
            verifier.verify_for_time(token, &alg, get_time()).unwrap();

        assert_eq!(my_claims, claims);
        assert_eq!(header.get("kid").unwrap(), "kid1234");
        assert_eq!(header.get("my_hdr").unwrap(), "my_hdr_val");
    }
}

#[test]
#[should_panic(expected = "InvalidInput")]
fn dont_allow_sign_with_verify_algorithm() {
    let my_claims = json!({
        "sub": "b@b.com",
        "company": "ACME",
        "exp": get_time() + 10000,
    });
    let keypair = include_bytes!("private_rsa_key_pkcs1.pem");

    let verify_alg = Algorithm::new_rsa_pem_verifier(AlgorithmID::RS256, keypair).unwrap();

    let header = json!({"alg": verify_alg.name()});
    let _token = jwt::encode(&header, &my_claims, &verify_alg).unwrap();
}

#[test]
#[should_panic(expected = "InvalidInput")]
fn dont_allow_verify_with_sign_algorithm() {
    let my_claims = json!({
        "sub": "b@b.com",
        "company": "ACME",
        "exp": get_time() + 10000,
    });
    let keypair = include_bytes!("private_rsa_key_pkcs1.pem");

    let sign_alg = Algorithm::new_rsa_pem_signer(AlgorithmID::RS256, keypair).unwrap();

    let header = json!({"alg": sign_alg.name()});
    let token = jwt::encode(&header, &my_claims, &sign_alg).unwrap();

    let verifier = Verifier::create().build().unwrap();
    let _claims: Value = verifier.verify(token, &sign_alg).unwrap();
}

#[test]
fn rsa_modulus_exponent() {
    let privkey = include_bytes!("private_rsa_key_pkcs1.pem");
    let sign_alg = Algorithm::new_rsa_pem_signer(AlgorithmID::RS256, privkey).unwrap();
    let my_claims = json!({
        "sub": "b@b.com",
        "company": "ACME",
        "exp": get_time() + 10000,
    });
    let n = "yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ";
    let e = "AQAB";

    let header = json!({"alg": sign_alg.name() });
    let token = jwt::encode(&header, &my_claims, &sign_alg).unwrap();

    let verify_alg = Algorithm::new_rsa_n_e_b64_verifier(AlgorithmID::RS256, n, e).unwrap();
    let verifier = Verifier::create().build().unwrap();
    let _claims: Value = verifier.verify(token, &verify_alg).unwrap();
}

// https://jwt.io/ is often used for examples so ensure their example works with jsonwebtoken
#[test]
fn roundtrip_with_jwtio_example_jey() {
    let privkey_pem = include_bytes!("private_rsa_key_jwtio_pkcs1.pem");
    let pubkey_pem = include_bytes!("public_rsa_key_jwtio_pkcs1.pem");

    let my_claims = json!({
        "sub": "b@b.com",
        "company": "ACME",
        "exp": get_time() + 10000,
    });

    for &id in RSA_ALGORITHMS {
        let alg = Algorithm::new_rsa_pem_signer(id, privkey_pem).unwrap();

        let header = json!({"alg": alg.name()});
        let token = jwt::encode(&header, &my_claims, &alg).unwrap();

        let alg = Algorithm::new_rsa_pem_verifier(id, pubkey_pem).unwrap();
        let verifier = Verifier::create().build().unwrap();
        let claims: Value = verifier.verify(token, &alg).unwrap();

        assert_eq!(my_claims, claims);
    }
}