See JSON Web Tokens for more information on what JSON Web Tokens are.
Add the following to Cargo.toml:
toml
jsonwebtoken = "7"
serde = {version = "1.0", features = ["derive"] }
The minimum required Rust version is 1.46.
This library currently supports the following:
Complete examples are available in the examples directory: a basic one and one with a custom header.
In terms of imports and structs: ```rust use serde::{Serialize, Deserialize}; use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
/// Our claims struct, it needs to derive Serialize
and/or Deserialize
struct Claims { sub: String, company: String, exp: usize, } ```
The claims fields which can be validated. (see validation) ```rust
struct Claims { aud: String, // Optional. Audience exp: usize, // Required (validate_exp defaults to true in validation). Expiration time (as UTC timestamp) iat: usize, // Optional. Issued at (as UTC timestamp) iss: String, // Optional. Issuer nbf: usize, // Optional. Not Before (as UTC timestamp) sub: String, // Optional. Subject (whom token refers to) } ```
The default algorithm is HS256, which uses a shared secret.
rust
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;
All the parameters from the RFC are supported but the default header only has typ
and alg
set.
If you want to set the kid
parameter or change the algorithm for example:
rust
let mut header = Header::new(Algorithm::HS512);
header.kid = Some("blabla".to_owned());
let token = encode(&header, &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;
Look at examples/custom_header.rs
for a full working example.
rust
// HS256
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;
// RSA
let token = encode(&Header::new(Algorithm::RS256), &my_claims, &EncodingKey::from_rsa_pem(include_bytes!("privkey.pem"))?)?;
Encoding a JWT takes 3 parameters:
Header
structWhen using HS256, HS2384 or HS512, the key is always a shared secret like in the example above. When using RSA/EC, the key should always be the content of the private key in the PEM or DER format.
If your key is in PEM format, it is better performance wise to generate the EncodingKey
once in a lazy_static
or
something similar and reuse it.
rust
// `token` is a struct with 2 fields: `header` and `claims` where `claims` is your own struct.
let token = decode::<Claims>(&token, &DecodingKey::from_secret("secret".as_ref()), &Validation::default())?;
decode
can error for a variety of reasons:
As with encoding, when using HS256, HS2384 or HS512, the key is always a shared secret like in the example above. When using RSA/EC, the key should always be the content of the public key in the PEM or DER format.
In some cases, for example if you don't know the algorithm used or need to grab the kid
, you can choose to decode only the header:
rust
let header = decode_header(&token)?;
This does not perform any signature verification or validate the token claims.
You can also decode a token using the public key components of a RSA key in base64 format. The main use-case is for JWK where your public key is in a JSON format like so:
json
{
"kty":"RSA",
"e":"AQAB",
"kid":"6a7a119f-0876-4f7e-8d0f-bf3ea1391dd8",
"n":"yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ"
}
rust
// `token` is a struct with 2 fields: `header` and `claims` where `claims` is your own struct.
let token = decode::<Claims>(&token, &DecodingKey::from_rsa_components(jwk["n"], jwk["e"]), &Validation::new(Algorithm::RS256))?;
If your key is in PEM format, it is better performance wise to generate the DecodingKey
once in a lazy_static
or
something similar and reuse it.
jsonwebtoken
currently only supports PKCS8 format for private EC keys. If your key has BEGIN EC PRIVATE KEY
at the top,
this is a SEC1 type and can be converted to PKCS8 like so:
bash
openssl pkcs8 -topk8 -nocrypt -in sec1.pem -out pkcs8.pem
This library validates automatically the exp
claim and nbf
is validated if present. You can also validate the sub
, iss
and aud
but
those require setting the expected value in the Validation
struct.
Since validating time fields is always a bit tricky due to clock skew,
you can add some leeway to the iat
, exp
and nbf
validation by setting the leeway
field.
Last but not least, you will need to set the algorithm(s) allowed for this token if you are not using HS256
.
```rust
struct Validation {
pub leeway: u64, // Default: 0
pub validateexp: bool, // Default: true
pub validatenbf: bool, // Default: false
pub aud: Option
```rust use jsonwebtoken::{Validation, Algorithm};
// Default validation: the only algo allowed is HS256 let validation = Validation::default(); // Quick way to setup a validation where only the algorithm changes let validation = Validation::new(Algorithm::HS512); // Adding some leeway (in seconds) for exp and nbf checks let mut validation = Validation {leeway: 60, ..Default::default()}; // Checking issuer let mut iss = std::collections::HashSet::new(); iss.insert("issuer".tostring()); let mut validation = Validation {iss: Some(iss), ..Default::default()}; // Setting audience let mut validation = Validation::default(); validation.setaudience(&"Me"); // string validation.set_audience(&["Me", "You"]); // array of strings ```
Look at examples/validation.rs
for a full working example.