PASETO in Rust — paseto-rs Quickstart

Quickstart for using paseto-rs to issue and verify PASETO v4.public tokens in Rust, including key generation and footer handling.

Implementation

Detailed Explanation

Rust has excellent PASETO support via the rusty_paseto crate (sometimes called paseto-rs). It supports v1-v4, both local and public, plus PASERK.

Cargo.toml:

[dependencies]
rusty_paseto = { version = "0.7", features = ["v4_public", "v4_local"] }
serde_json = "1"

Generating a v4.public key pair:

use rusty_paseto::core::{Key, V4, Public};

let private = Key::<64>::try_new_random()?; // Ed25519 secret
let public  = Key::<32>::try_from(&private[32..])?; // last 32 bytes are the public part

In practice, use the high-level PasetoBuilder API which handles key types for you.

Issuing a v4.public token:

use rusty_paseto::prelude::*;

let token = PasetoBuilder::<V4, Public>::default()
    .set_claim(IssuerClaim::from("https://auth.example.com"))
    .set_claim(SubjectClaim::from("user-12345"))
    .set_claim(AudienceClaim::from("https://api.example.com"))
    .set_claim(ExpirationClaim::try_from("2026-01-01T00:00:00Z")?)
    .build(&private_key)?;

The result is a string like v4.public.eyJpc3MiOi....

Verifying a v4.public token:

use rusty_paseto::prelude::*;

let parsed = PasetoParser::<V4, Public>::default()
    .check_claim(IssuerClaim::from("https://auth.example.com"))
    .check_claim(AudienceClaim::from("https://api.example.com"))
    .parse(&token, &public_key)?;

let payload: serde_json::Value = serde_json::from_value(parsed)?;

The parser refuses to return claims if the signature is invalid or any check_claim fails — so you can't accidentally trust an unverified payload.

Footers:

Add a footer at build time with .set_footer(Footer::from("{"kid":"key-1"}")) and read it from a parsed token via the parser API. Footers are validated as part of the signature.

Why Rust for PASETO:

Rust's strong type system maps well onto PASETO's version+purpose model — PasetoBuilder<V4, Public> and PasetoBuilder<V4, Local> are different types, so you literally can't accidentally swap them. The library leans into this to prevent misuse at compile time.

Use Case

A Rust microservice issues v4.public tokens with rusty_paseto, attaching a kid footer; downstream services verify with the matching public key configured at startup.

Try It — PASETO Decoder

Open full tool