Crate pasta_tokens
source ·Expand description
PASETO - Platform Agnostic Security Tokens.
- @conradludgate: “hmm, actually, I might switch to using something like paseto”
- @ellie: “It sounds like a type of pasta”
Paseto is everything you love about JOSE (JWT, JWE, JWS) without any of the many design deficits that plague the JOSE standards. See more about PASETO in the specification
Features
v4
: Enables all V4 PASETO/PASERK functions.v4-paseto
v4-local
: V4 symmetric encrypted tokensv4-public
: V4 asymmetric signed tokens
v4-paserk
v4-id
: V4 Key IDsv4-pke
: V4 Sealed Keysv4-pbkw
: V4 Password wrapped keysv4-wrap
: v4 Wrapped Keys
v3
: Enables all V3 PASETO/PASERK functions.v3-paseto
v3-local
: V3 symmetric encrypted tokensv3-public
: V3 asymmetric signed tokens
v3-paserk
v3-id
: V3 Key IDsv3-pke
: V3 Sealed Keysv3-pbkw
: V3 Password wrapped keysv3-wrap
: v3 Wrapped Keys
Examples
use pasta_tokens::{v4, paserk::k4, purpose::public::Public, Json};
#[derive(serde::Serialize, serde::Deserialize)]
struct Footer {
/// The ID of the key used to sign the PASETO.
/// A footer should only contain types that are `SafeForFooter`
kid: k4::KeyId<Public>,
}
#[derive(serde::Serialize, serde::Deserialize)]
struct Payload {
/// The expiration date of the token
#[serde(with = "time::serde::rfc3339", rename = "exp")]
expiration: time::OffsetDateTime,
/// The subject of the token
#[serde(rename = "sub")]
user_id: uuid::Uuid,
}
// load your secret key
let secret_key = hex::decode("407796f4bc4b8184e9fe0c54b336822d34823092ad873d87ba14c3efb9db8c1d").unwrap();
let secret_key = v4::SecretKey::from_secret_key(secret_key.try_into().unwrap());
let user_id = uuid::Uuid::new_v4();
// create the token payload and footer.
let token = v4::UnsignedToken::new(Payload {
// expires in 1 hour
expiration: time::OffsetDateTime::now_utc() + time::Duration::hours(1),
user_id,
})
.with_footer(Json(Footer {
kid: secret_key.public_key().to_id(),
}))
// sign with the secret key
.sign(&secret_key)
.unwrap()
.to_string();
// Send off the token to the client
println!("{token}");
// "v4.public.eyJleHAiOiIyMDIzLTEwLTAxVDE0OjQ4OjI2LjM0NjA5MloiLCJzdWIiOiIxOTBhZjFmYS1lZGVlLTRiNGUtOGQxMC05ZmUwZjQ1ZGQ5OTQifXo-Vsr45NroJZ9pLkuN3xcxgFncGF3eject5GdZH7WwTEfCgmo6hD-zNh0txsLvZi1vC601oNCgXq_2cK4XKQw.eyJraWQiOiJrNC5waWQuQUdQQ09CUkI4UHowQ3dNOFFfQnNVUEw0OF8zZjRUbE0yc2Z0R3Y0ejkzVFkifQ"
// load your public keys
let public_key = hex::decode("b7715bd661458d928654d3e832f53ff5c9480542e0e3d4c9b032c768c7ce6023").unwrap();
let public_key = v4::PublicKey::from_public_key(&public_key).unwrap();
// keep a key cache of key IDs to public keys.
// this will let you securely rotate your secret keys
// and still validate multiple public keys safely
let keys = std::collections::HashMap::from([
(public_key.to_id(), public_key)
]);
// Parse the token from the client
let token: v4::SignedToken<Json<Footer>> = token.parse().expect("should be a valid token format");
// using the key ID, search for the public key
let key = &keys[&token.unverified_footer().0.kid];
// verify the token signature
let token: v4::VerifiedToken<Payload, _> = token.verify(key).expect("token should be signed by us");
// check if the token has expired
assert!(token.message.expiration > time::OffsetDateTime::now_utc());
// proceed to use the payload as you wish!
assert_eq!(token.message.user_id, user_id);
Modules
- PASETO Message encodings. Currently supports
Json
- PASETO Keys
- Generic Tokens
- PASETO V3 using only NIST approved algorithms
- PASETO V4 using only algorithms that are provided by libsodium
Structs
Json
is a type wrapper to implementFooter
for all types that implementserde::Serialize
andserde::Deserialize
Enums
- Error returned for all PASETO and PASERK operations that can fail
Traits
- Encoding scheme for PASETO footers.