#jwt #twist #token #json #header #claim #encode-decode

twist-jwt

An implementation of RFC7519 JSON Web Token (JWT)

4 releases (2 breaking)

Uses old Rust 2015

0.3.1 Mar 21, 2017
0.3.0 Mar 19, 2017
0.2.0 Mar 16, 2017
0.1.0 Mar 10, 2017

#2 in #twist


Used in 2 crates

MIT/Apache

49KB
975 lines

twist-jwt

An implementation of RFC7519 JSON Web Token (JWT).


lib.rs:

JSON Web Token (JWT) implementation for twist.

Examples

Encode/Decode the sample token from jwt.io

#
#
#[derive(Clone, Deserialize, PartialEq, Serialize)]
pub struct Claims {
    pub sub: String,
    pub name: String,
    pub admin: bool,
}

// Our super 'secret'
let secret = "secret".as_bytes();

// Sample Token from jwt.io.
let actual = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\
    eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.\
    TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";

// Default JOSE Header (alg: HS256, typ: 'JWT').
let mut header: Header = Default::default();

// The jwt.io sample claims.  This can really be anything as long as its
// 'Clone + Deserialize + Serialize'.
let claims = Claims {
    sub: "1234567890".to_string(),
    name: "John Doe".to_string(),
    admin: true,
};

// Encode the header and claims with the given secret, and ensure it's the same as the sample
// token.
let mut token = String::new();
match encode::jwt(&header, &claims, &secret) {
    Ok(tok) => {
        assert!(tok == actual);
        token = tok;
    },
    Err(_) => assert!(false),
}

// Now decode the token from above into it's parts.
match decode::jwt::<Claims>(&token, &secret, Algorithm::HS256) {
    Ok(token_data) => {
        assert!(token_data.header() == header);
        assert!(token_data.claims() == claims);
    }
    Err(_) => assert!(false),
}

Encode/Decode/Verify with a set of registered claims.

#
#
#[derive(Clone, Deserialize, PartialEq, Serialize)]
pub struct Claims {
    pub iss: String,
    pub sub: String,
    pub aud: String,
    pub exp: DateTime<UTC>,
    pub nbf: DateTime<UTC>,
    pub iat: DateTime<UTC>,
    pub jti: String,
}

impl Default for Claims {
    fn default() -> Claims {
        Claims {
            iss: String::new(),
            sub: String::new(),
            aud: String::new(),
            exp: UTC::now(),
            nbf: UTC::now(),
            iat: UTC::now(),
            jti: String::new(),
        }
    }
}

impl verify::HasRegistered for Claims {
    fn iss(&self) -> Option<String> {
        Some(self.iss.clone())
    }

    fn sub(&self) -> Option<String> {
        Some(self.sub.clone())
    }

    fn aud(&self) -> Option<String> {
        Some(self.aud.clone())
    }

    fn exp(&self) -> Option<DateTime<UTC>> {
        Some(self.exp.clone())
    }

    fn nbf(&self) -> Option<DateTime<UTC>> {
        Some(self.nbf.clone())
    }

    fn iat(&self) -> Option<DateTime<UTC>> {
        Some(self.iat.clone())
    }

    fn jti(&self) -> Option<String> {
        Some(self.jti.clone())
    }
}

// Our super 'secret'
let secret = "secret".as_bytes();

// Default JOSE Header (alg: HS256, typ: 'JWT').
let header: Header = Default::default();

// Our time based claims.
let now: DateTime<UTC> = UTC::now();
let exp = now.checked_add_signed(Duration::minutes(10)).expect("invalid exp");
let nbf = now.checked_sub_signed(Duration::seconds(10)).expect("invalid nbf");

// The jwt.io sample claims.  This can really be anything as long as its
// 'Clone + Deserialize + Serialize'.
let claims = Claims {
    iss: "me".to_string(),
    sub: "me".to_string(),
    aud: "you".to_string(),
    exp: exp,
    nbf: nbf,
    iat: now,
    jti: "my unique id".to_string(),
};

// Encode the header and claims with the given secret.
let mut token = String::new();
match encode::jwt(&header, &claims, &secret) {
    Ok(tok) => token = tok,
    Err(_) => assert!(false),
}

// Now decode the token from above into it's parts.
let mut unverified: Claims = Default::default();

match decode::jwt::<Claims>(&token, &secret, Algorithm::HS256) {
    Ok(token_data) => {
        assert!(token_data.header() == header);
        assert!(token_data.claims() == claims);
        unverified = token_data.claims();
    }
    Err(_) => assert!(false),
}

// Verify the claims
assert!(verify::claims(&unverified, &claims, verify::ALL));
// Adjust the unverified.
unverified.iss = "notme".to_string();
// Verify should fail.
assert!(!verify::claims(&unverified, &claims, verify::ALL));

Dependencies

~20–30MB
~534K SLoC