//! # Getting started //! This library has two ways of working with tokens. The first is the [`local`] and [`public`] module, //! which the below examples make use of. These use the latest version of PASETO for tokens, //! along with [`claims::Claims`], to enable a straightforward way of defining common claims. //! [`claims::ClaimsValidationRules`] lets you define validation rules, that are covered when using //! the [`local`] and [`public`] module. Using these modules means that validation of registered //! claims is handled automatically. //! //! If more control over the input is needed, and validation is handled manually, the [`version4`]/[`version2`] //! module provide a lower-level interface, where payloads are be provided as byte-slices. //! //! NOTE: [`claims`], [`local`] and [`public`] modules are __only available with default-features enabled__. //! ## Creating and verifying public tokens //! ```rust //! use pasetors::claims::{Claims, ClaimsValidationRules}; //! use pasetors::keys::{Generate, AsymmetricKeyPair, AsymmetricSecretKey, AsymmetricPublicKey}; //! use pasetors::{public, Public, version4::V4}; //! use pasetors::token::{UntrustedToken, TrustedToken}; //! use core::convert::TryFrom; //! //! // Setup the default claims, which include `iat` and `nbf` as the current time and `exp` of one hour. //! // Add a custom `data` claim as well. //! let mut claims = Claims::new()?; //! claims.add_additional("data", "A public, signed message")?; //! //! // Generate the keys and sign the claims. //! let kp = AsymmetricKeyPair::::generate()?; //! let pub_token = public::sign(&kp.secret, &claims, None, Some(b"implicit assertion"))?; //! //! // Decide how we want to validate the claims after verifying the token itself. //! // The default verifies the `nbf`, `iat` and `exp` claims. `nbf` and `iat` are always //! // expected to be present. //! // NOTE: Custom claims, defined through `add_additional()`, are not validated. This must be done //! // manually. //! let validation_rules = ClaimsValidationRules::new(); //! let untrusted_token = UntrustedToken::::try_from(&pub_token)?; //! let trusted_token = public::verify(&kp.public, &untrusted_token, &validation_rules, None, Some(b"implicit assertion"))?; //! assert_eq!(&claims, trusted_token.payload_claims().unwrap()); //! //! let claims = trusted_token.payload_claims().unwrap(); //! //! println!("{:?}", claims.get_claim("data")); //! println!("{:?}", claims.get_claim("iat")); //! //! # Ok::<(), pasetors::errors::Error>(()) //! ``` //! ## Creating and verifying local tokens //! ```rust //! use pasetors::claims::{Claims, ClaimsValidationRules}; //! use pasetors::keys::{Generate, SymmetricKey}; //! use pasetors::{local, Local, version4::V4}; //! use pasetors::token::UntrustedToken; //! use core::convert::TryFrom; //! //! // Setup the default claims, which include `iat` and `nbf` as the current time and `exp` of one hour. //! // Add a custom `data` claim as well. //! let mut claims = Claims::new()?; //! claims.add_additional("data", "A secret, encrypted message")?; //! //! // Generate the key and encrypt the claims. //! let sk = SymmetricKey::::generate()?; //! let token = local::encrypt(&sk, &claims, None, Some(b"implicit assertion"))?; //! //! // Decide how we want to validate the claims after verifying the token itself. //! // The default verifies the `nbf`, `iat` and `exp` claims. `nbf` and `iat` are always //! // expected to be present. //! // NOTE: Custom claims, defined through `add_additional()`, are not validated. This must be done //! // manually. //! let validation_rules = ClaimsValidationRules::new(); //! let untrusted_token = UntrustedToken::::try_from(&token)?; //! let trusted_token = local::decrypt(&sk, &untrusted_token, &validation_rules, None, Some(b"implicit assertion"))?; //! assert_eq!(&claims, trusted_token.payload_claims().unwrap()); //! //! let claims = trusted_token.payload_claims().unwrap(); //! //! println!("{:?}", claims.get_claim("data")); //! println!("{:?}", claims.get_claim("iat")); //! //! # Ok::<(), pasetors::errors::Error>(()) //! ``` //! ## Additional claims and their validation //! //! ### Setting registered claims and how to validate them //! ```rust //! use pasetors::claims::{Claims, ClaimsValidationRules}; //! //! // `iat`, `nbf` and `exp` have been set automatically, but could also be overridden. //! let mut claims = Claims::new()?; //! claims.issuer("paragonie.com")?; //! claims.subject("test")?; //! claims.audience("pie-hosted.com")?; //! claims.expiration("2039-01-01T00:00:00+00:00")?; //! claims.not_before("2038-04-01T00:00:00+00:00")?; //! claims.issued_at("2038-03-17T00:00:00+00:00")?; //! claims.token_identifier("87IFSGFgPNtQNNuw0AtuLttPYFfYwOkjhqdWcLoYQHvL")?; //! //! let mut validation_rules = ClaimsValidationRules::new(); //! validation_rules.validate_issuer_with("paragonie.com"); //! validation_rules.validate_subject_with("test"); //! validation_rules.validate_audience_with("pie-hosted.com"); //! validation_rules.validate_token_identifier_with("87IFSGFgPNtQNNuw0AtuLttPYFfYwOkjhqdWcLoYQHvL"); //! //! // The token has been set to be issued in the future and not valid yet, so validation fails. //! assert!(validation_rules.validate_claims(&claims).is_err()); //! # Ok::<(), pasetors::errors::Error>(()) //! ``` //! ### Non-expiring tokens //! ```rust //! use pasetors::claims::{Claims, ClaimsValidationRules}; //! //! // Non-expiring tokens //! let mut claims = Claims::new()?; //! claims.add_additional("data", "A public, signed message")?; //! claims.non_expiring(); //! // Now claims can be validated as non-expiring when we define the validation rule as: //! let mut validation_rules = ClaimsValidationRules::new(); //! validation_rules.allow_non_expiring(); //! //! # Ok::<(), pasetors::errors::Error>(()) //! ``` //! ## Footer with registered and custom claims //! ```rust //! use pasetors::paserk::{FormatAsPaserk, Id}; //! use pasetors::claims::{Claims, ClaimsValidationRules}; //! use pasetors::footer::Footer; //! use pasetors::keys::{Generate, AsymmetricKeyPair}; //! use pasetors::{public, Public, version4::V4}; //! use pasetors::token::UntrustedToken; //! use core::convert::TryFrom; //! //! // Generate the key used to later sign a token. //! let kp = AsymmetricKeyPair::::generate()?; //! // Serialize the public key to PASERK "pid". //! let mut pid = Id::from(&kp.public); //! // Add the "pid" to the "kid" claim of a footer. //! let mut footer = Footer::new(); //! footer.key_id(&pid); //! footer.add_additional("custom_footer_claim", "custom_value")?; //! //! let mut claims = Claims::new()?; //! let pub_token = public::sign(&kp.secret, &claims, Some(&footer), Some(b"implicit assertion"))?; //! //! // If we receive a token that needs to be verified, we can still try to parse a Footer from it //! // as long one was used during creation, if we don't know it beforehand. //! let validation_rules = ClaimsValidationRules::new(); //! let untrusted_token = UntrustedToken::::try_from(&pub_token)?; //! let trusted_token = public::verify(&kp.public, &untrusted_token, &validation_rules, None, Some(b"implicit assertion"))?; //! let trusted_footer = Footer::try_from(&trusted_token)?; //! //! let mut kid = String::new(); //! pid.fmt(&mut kid).unwrap(); //! assert_eq!(trusted_footer.get_claim("kid").unwrap().as_str().unwrap(), kid); //! //! # Ok::<(), pasetors::errors::Error>(()) //! ``` //! ## PASERK serialization //! ```rust //! use pasetors::paserk::FormatAsPaserk; //! use pasetors::keys::{Generate, SymmetricKey}; //! use pasetors::version4::V4; //! use core::convert::TryFrom; //! //! // Generate the key and serialize to and from PASERK. //! let sk = SymmetricKey::::generate()?; //! let mut paserk = String::new(); //! sk.fmt(&mut paserk).unwrap(); //! let sk = SymmetricKey::::try_from(paserk.as_str())?; //! //! # Ok::<(), pasetors::errors::Error>(()) //! ``` #![cfg_attr(not(feature = "std"), no_std)] #![forbid(unsafe_code)] #![deny(clippy::mem_forget)] #![warn( missing_docs, rust_2018_idioms, trivial_casts, unused_qualifications, overflowing_literals )] #![doc(html_root_url = "https://docs.rs/pasetors/0.6.7")] #![cfg_attr(docsrs, feature(doc_cfg))] #[macro_use] extern crate alloc; mod pae; /// Errors for token operations. pub mod errors; mod common; #[cfg(feature = "std")] /// Claims for tokens and validation thereof. pub mod claims; #[cfg(feature = "std")] /// Footer for tokens. pub mod footer; /// Keys used for PASETO tokens. pub mod keys; #[cfg(feature = "paserk")] /// PASERK key-wrapping and serialization. pub mod paserk; #[cfg(feature = "v2")] /// PASETO version 2 tokens. pub mod version2; #[cfg(feature = "v3")] /// PASETO version 3 tokens. pub mod version3; #[cfg(feature = "v4")] /// PASETO version 4 tokens. pub mod version4; /// Types for handling tokens. pub mod token; #[cfg(feature = "serde")] /// Serialization and deserialization support for various types. mod serde; mod version; /// Public and local tokens. pub use token::{Local, Public}; #[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "v4"))))] #[cfg(all(feature = "std", feature = "v4"))] /// PASETO public tokens with [`version4`], using [`claims::Claims`]. pub mod public { use super::*; use crate::claims::{Claims, ClaimsValidationRules}; use crate::errors::Error; use crate::footer::Footer; use crate::keys::{AsymmetricPublicKey, AsymmetricSecretKey}; use crate::token::{TrustedToken, UntrustedToken}; use crate::version4::V4; /// Create a public token using the latest PASETO version (v4). pub fn sign( secret_key: &AsymmetricSecretKey, message: &Claims, footer: Option<&Footer>, implicit_assert: Option<&[u8]>, ) -> Result { match footer { Some(f) => crate::version4::PublicToken::sign( secret_key, message.to_string()?.as_bytes(), Some(f.to_string()?.as_bytes()), implicit_assert, ), None => crate::version4::PublicToken::sign( secret_key, message.to_string()?.as_bytes(), None, implicit_assert, ), } } /// Verify a public token using the latest PASETO version (v4). If verification passes, /// validate the claims according to the `validation_rules`. pub fn verify( public_key: &AsymmetricPublicKey, token: &UntrustedToken, validation_rules: &ClaimsValidationRules, footer: Option<&Footer>, implicit_assert: Option<&[u8]>, ) -> Result { let mut trusted_token = match footer { Some(f) => crate::version4::PublicToken::verify( public_key, token, Some(f.to_string()?.as_bytes()), implicit_assert, )?, None => crate::version4::PublicToken::verify(public_key, token, None, implicit_assert)?, }; let claims = Claims::from_string(trusted_token.payload())?; validation_rules.validate_claims(&claims)?; trusted_token.set_payload_claims(claims); Ok(trusted_token) } } #[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "v4"))))] #[cfg(all(feature = "std", feature = "v4"))] /// PASETO local tokens with [`version4`], using [`claims::Claims`]. pub mod local { use super::*; use crate::claims::{Claims, ClaimsValidationRules}; use crate::errors::Error; use crate::footer::Footer; use crate::keys::SymmetricKey; use crate::token::{TrustedToken, UntrustedToken}; use crate::version4::V4; /// Create a local token using the latest PASETO version (v4). pub fn encrypt( secret_key: &SymmetricKey, message: &Claims, footer: Option<&Footer>, implicit_assert: Option<&[u8]>, ) -> Result { match footer { Some(f) => crate::version4::LocalToken::encrypt( secret_key, message.to_string()?.as_bytes(), Some(f.to_string()?.as_bytes()), implicit_assert, ), None => crate::version4::LocalToken::encrypt( secret_key, message.to_string()?.as_bytes(), None, implicit_assert, ), } } /// Verify a local token using the latest PASETO version (v4). If verification passes, /// validate the claims according to the `validation_rules`. pub fn decrypt( secret_key: &SymmetricKey, token: &UntrustedToken, validation_rules: &ClaimsValidationRules, footer: Option<&Footer>, implicit_assert: Option<&[u8]>, ) -> Result { let mut trusted_token = match footer { Some(f) => crate::version4::LocalToken::decrypt( secret_key, token, Some(f.to_string()?.as_bytes()), implicit_assert, )?, None => crate::version4::LocalToken::decrypt(secret_key, token, None, implicit_assert)?, }; let claims = Claims::from_string(trusted_token.payload())?; validation_rules.validate_claims(&claims)?; trusted_token.set_payload_claims(claims); Ok(trusted_token) } }