Expand description

No Way, Jose!

A library to work with Javascript Object Signing and Encryption (JOSE), including:

  • JSON Web Tokens (JWT)
  • JSON Web Signature (JWS)
  • JSON Web Encryption (JWE)
  • JSON Web Algorithms (JWA)
  • JSON Web Keys (JWK)

Examples

Sign a token with HS256, then encrypt with A256GCMKW and A256GCM

use no_way::{ClaimsSet, RegisteredClaims, JWT, JWE};
use no_way::jwk;
use no_way::jwe::Encrypted;
use no_way::jwa::{kma, cea, sign};
use serde::{Serialize, Deserialize};

// Define our own private claims
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
struct PrivateClaims {
    company: String,
    department: String,
}

let signing_key = jwk::OctetKey::new("secret".to_string().into_bytes());

let expected_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\
       eyJpc3MiOiJodHRwczovL3d3dy5hY21lLmNvbS8iLCJzdWIiOiJKb2huIERvZSIsImF1ZCI6Imh0dHBzOi8vYWNtZ\
       S1jdXN0b21lci5jb20vIiwibmJmIjoxMjM0LCJjb21wYW55IjoiQUNNRSIsImRlcGFydG1lbnQiOiJUb2lsZXQgQ2\
       xlYW5pbmcifQ.VFCl2un1Kc17odzOe2Ehf4DVrWddu3U4Ux3GFpOZHtc";

let expected_claims = ClaimsSet::<PrivateClaims> {
    registered: RegisteredClaims {
        issuer: Some("https://www.acme.com/".into()),
        subject: Some("John Doe".to_string()),
        audience: Some("https://acme-customer.com/".into()),
        not_before: Some(1234.try_into().unwrap()),
        ..Default::default()
    },
    private: PrivateClaims {
        department: "Toilet Cleaning".to_string(),
        company: "ACME".to_string(),
    },
};

let jwt = JWT::new(expected_claims.clone());

let jws_token = jwt.encode::<sign::HS256>(&signing_key).unwrap();
assert_eq!(expected_token, jws_token.to_string());

// Encrypt the token

// You would usually have your own AES key for this, but we will use a zeroed key as an example
let key = jwk::OctetKey::new(vec![0; 256 / 8]);

/// We need to create a nonce for AES GCM encryption.
/// You must take care NOT to reuse the nonce.
/// You can simply treat the nonce as a 96 bit
/// counter that is incremented after every use
///
/// In this case, we're using a 64bit counter + a 32bit random prefix tag
fn generate_nonce() -> [u8; 96/8] {
    static NONCE: AtomicU64 = AtomicU64::new(0);
    // use some lazy random generation so each service has a separate tag
    static TAG: u32 = 0xDEADCAFE;

    // fetch and increment the nonce counter
    let nonce = NONCE.fetch_add(1, Ordering::Release);

    // collect the bytes together and return them
    let mut output = [0; 96/8];
    output[0..32/8].copy_from_slice(&TAG.to_be_bytes());
    output[32/8..].copy_from_slice(&nonce.to_be_bytes());
    output
}
let nonce = generate_nonce();

// Construct the JWE
let jwe = JWE::new(jws_token.clone());

// Encrypt
let encrypted_jwe = jwe.encrypt::<
    cea::A256GCM,   // encrypt the contents with AES256 GCM
    kma::A256GCMKW, // perform key wrapping with AES256 GCM
>(&key, nonce).unwrap();

let jwe_token = encrypted_jwe.to_string();

// Now, send `token` to your clients

// ... some time later, we get token back!
let encrypted_jwe: Encrypted<kma::A256GCMKW> = jwe_token.parse().unwrap();

// Decrypt
let decrypted_jwe: JWE<_> = encrypted_jwe.decrypt::<_, cea::A256GCM>(&key).unwrap();

// Verify the JWT signature
let decoded_jwt = decrypted_jwe.payload.verify::<sign::HS256>(&signing_key).unwrap();

assert_eq!(decoded_jwt.payload, expected_claims);

Modules

Errors returned will be converted to one of the structs in this module.
JSON Web Signatures, including JWT signing and headers

Structs

Options for claims presence validation
A collection of claims, both registered and your custom private claims.
A [CompactPart] type that parses data as json using serde_json
Registered claims defined by RFC7519#4.1
Options for validating temporal claims
Wrapper around OffsetDateTime to allow us to do custom de(serialization)
Options for claims validation

Enums

Defines whether a claim is required or not
Represents a choice between a single value or multiple string values.
Defines whether a claim is validated or not

Traits

A trait to describe how to parse components of a compact form JWS or JWE
A trait to describe how to produce components of a compact form JWS or JWE

Type Definitions

A convenience type alias of a JSON Web Encryption token in it’s decrypted form. It contains an encoded JWT as it’s contents.
A convenience type alias of a JSON Web Encryption token in it’s decoded form. It contains a ClaimsSet as it’s contents