GitHub CI Docs.rs

JWT-Simple (WIP)

A new JWT implementation for Rust that focuses on simplicity.

jwt-simple is unopinionated and supports all commonly deployed authentication and signature algorithms:

jwt-simple uses only pure Rust implementations, and compiled out of the box to WebAssembly/WASI. It is fully compatible with Fastly's Compute@Edge service.

Usage

cargo.toml

toml [dependencies] jwt-simple = "0.1"

Authentication (symmetric, HS* JWT algorithms) example

Authentication schemes uses the same key for creating and verifying tokens. In other words, both parties need to be ultimately trusting each other, or else the verifier could also create arbitrary tokens.

Keys and tokens creation

Key creation:

```rust use jwt_simple::prelude::*;

// create a new key for the HS256 JWT algorithm let key = HS256Key::generate(); ```

A key can be exported as bytes with key.to_bytes(), and restored with HS256Key::from_bytes().

Token creation:

rust /// create claims valid for 2 hours let claims = Claims::create(Duration::from_hours(2)); let token = key.authenticate(claims)?;

Done!

Token verification

rust let claims = key.verify_token::<NoCustomClaims>(&token, None)?;

No additional steps required.

Key expiration, start time, authentication tag, etc. are automatically performed. The function call fails with JWTError::InvalidAuthenticationTag if the authentication tag is invalid for the given key.

The full set of claims can be inspected in the claims object if necessary. NoCustomClaims means that only the standard set of claims is used by the application, but application-defined claims are also supported.

Extra verification steps can optionally be enabled via the ValidationOptions structure:

```rust let mut options = VerificationOptions::default(); // Accept tokens that will only be valid in the future options.acceptfuture = true; // accept tokens even if they have expired up to 15 minutes after the deadline options.timetolerance = Some(Duration::frommins(15)); // reject tokens if they were issued more than 1 hour ago options.maxvalidity = Some(Duration::fromhours(1)); // reject tokens if they don't come from a specific issuer options.requiredissuer = Some("example app".to_string()); // see the documentation for the full list of available options

let claims = key.verify_token::(&token, options)?; ```

Signatures (asymmetric, RS*, PS*, ES* and EdDSA algorithms) example

A signature requires a key pair: a secret key used to create tokens, and a public key, that can only verify them.

Always use a signature scheme if both parties do not ultimately trust each other, such as tokens exchanged between clients and API providers.

Key pairs and tokens creation

Key creation:

```rust use jwt_simple::prelude::*;

// create a new key pair for the ES256 JWT algorithm let key_pair = ES256KeyPair::generate();

// a public key can be extracted from a key pair: let publickey = keypair.public_key(); ```

Keys can be exported as bytes for later reuse, and imported from bytes or, for RSA, from individual parameters, DER-encoded data or PEM-encoded data.

RSA key pair creation, using OpenSSL and PEM importation:

sh openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -outform PEM -pubout -out public.pem

rust let key_pair = RS384KeyPair::from_pem(private_pem_file_content)?; let public_key = RSA384PublicKey::from_pem(public_pem_file_content)?;

Token creation and verification work the same way as with HS* algorithms, except that tokens are created with a key pair, and verified using the corresponding public key.

Token creation:

rust /// create claims valid for 2 hours let claims = Claims::create(Duration::from_hours(2)); let token = key_pair.sign(claims)?;

Token verification:

rust let claims = public_key.verify_token::<NoCustomClaims>(&token, None)?;

Available verification options are identical to the ones used with symmetric algorithms.

Advanced usage

Custom claims

Claim objects support all the standard claims by default, and they can be set directly or via convenient helpers:

rust let claims = Claims::create(Duration::from_hours(2)). with_issuer("Example issuer").with_subject("Example subject");

But application-defined claims can also be defined. These simply have to be present in a serializable type:

``rust // this requires theserde` crate

[derive(Serialize, Deserialize)]

struct MyAdditionalData { userisadmin: bool, usercountry: String, } let myadditionaldata = MyAdditionalData { userisadmin: false, usercountry: "FR".to_string(), };

// claim creation with custom data let mut claims = Claims::withcustomclaims(myadditionaldata, Duration::from_secs(30));

// claim verification wit custom data. Note the presence of the custom data type. let claims = publickey.verifytoken::(&token, None); let useridadmin = claims.custom.useridadmin; ```