Crate rjwt

source ·
Expand description

Provides an Actor and (de)serializable Token struct which support authenticating JSON Web Tokens with a custom payload. See for more information on the JWT spec.

The provided Actor uses the ECDSA algorithm to sign tokens (using the ed25519_dalek crate).

This library differs from other JWT implementations in that it allows for recursive Tokens.

Note that if the same (host, actor) pair is specified multiple times in the token chain, only the latest is returned by [Claims::get].


use rjwt::*;

struct Resolver {
    hostname: String,
    actors: HashMap<String, Actor<String>>,
    peers: Vec<Self>,
// ...

impl Resolve for Resolver {
    type HostId = String;
    type ActorId = String;
    type Claims = String;

    async fn resolve(&self, host: &Self::HostId, actor_id: &Self::ActorId) -> Result<Actor<Self::ActorId>, Error> {
        if host == &self.hostname {
            self.actors.get(actor_id).cloned().ok_or_else(|| Error::fetch(actor_id))
        } else if let Some(peer) = self.peers.iter().filter(|p| &p.hostname == host).next() {
            peer.resolve(host, actor_id).await
        } else {

let now = SystemTime::now();

// Say that Bob is a user on
let bobs_id = "bob".to_string();
let example_dot_com = "".to_string();

let actor_bob = Actor::new(bobs_id.clone());
let example = Resolver::new(example_dot_com.clone(), [actor_bob.clone()], vec![]);

// Bob makes a request through the app.
let retailer_dot_com = "".to_string();
let retail_app = Actor::new("app".to_string());
let retailer = Resolver::new(

// The app makes a request to Bob's bank.
let bank_account = Actor::new("bank".to_string());
let bank = Resolver::new(
    vec![example, retailer.clone()]);

// First, issues a token to authenticate Bob.
let bobs_claim = String::from("I am Bob and may debit my account");

// This requires constructing the token...
let bobs_token = Token::new(

// and signing it with Bob's private key.
let bobs_token = actor_bob.sign_token(bobs_token).expect("signed token");

// Then, validates the token...
let bobs_token = block_on(retailer.verify(bobs_token.into_jwt(), now)).expect("claims");
assert!(bobs_token.get_claim(&example_dot_com, &bobs_id).expect("claim").starts_with("I am Bob"));

// and adds its own claim, that Bob owes it $1.
let retailer_claim = String::from("Bob spent $1 on");
let retailer_token = retail_app.consume_and_sign(
    now).expect("signed token");

assert_eq!(retailer_token.get_claim(&retailer_dot_com,, Some(&retailer_claim));
assert_eq!(retailer_token.get_claim(&example_dot_com,, Some(&bobs_claim));

// Finally, Bob's bank verifies the token...
let retailer_token_as_received = block_on(bank.verify(retailer_token.jwt().to_string(), now)).expect("claims");
assert_eq!(retailer_token, retailer_token_as_received);

// to authenticate that the request came from Bob...
    .get_claim(&example_dot_com, &bobs_id)
    .starts_with("I am Bob and may debit my account"));

// via
assert!(retailer_token_as_received.get_claim(&retailer_dot_com,"claim").starts_with("Bob spent $1"));


  • An actor with an identifier of type T and an ECDSA keypair used to sign tokens.
  • An error returned by a JWT operation
  • Ed25519 signature.
  • The data of a JWT including its (inherited) claims and encoded, signed representation.
  • ed25519 signing key which can be used to produce signatures.
  • The JSON Web Token wire format
  • An ed25519 public key.


  • The category of error returned by a JWT operation


  • Trait which defines how to fetch an Actor given its host and ID