no_way/
lib.rs

1//! # No Way, Jose!
2//!
3//! A library to work with Javascript Object Signing and Encryption (JOSE), including:
4//! * JSON Web Tokens (JWT)
5//! * JSON Web Signature (JWS)
6//! * JSON Web Encryption (JWE)
7//! * JSON Web Algorithms (JWA)
8//! * JSON Web Keys (JWK)
9//!
10//! # Examples
11//!
12//! ## Sign a token with HS256, then encrypt with A256GCMKW and A256GCM
13//!
14//! ```rust
15//! use no_way::{ClaimsSet, RegisteredClaims, JWT, JWE};
16//! use no_way::jwk;
17//! use no_way::jwe::Encrypted;
18//! use no_way::jwa::{kma, cea, sign};
19//! use serde::{Serialize, Deserialize};
20//!
21//! // Define our own private claims
22//! #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
23//! struct PrivateClaims {
24//!     company: String,
25//!     department: String,
26//! }
27//!
28//! let signing_key = jwk::OctetKey::new("secret".to_string().into_bytes());
29//!
30//! let expected_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\
31//!        eyJpc3MiOiJodHRwczovL3d3dy5hY21lLmNvbS8iLCJzdWIiOiJKb2huIERvZSIsImF1ZCI6Imh0dHBzOi8vYWNtZ\
32//!        S1jdXN0b21lci5jb20vIiwibmJmIjoxMjM0LCJjb21wYW55IjoiQUNNRSIsImRlcGFydG1lbnQiOiJUb2lsZXQgQ2\
33//!        xlYW5pbmcifQ.VFCl2un1Kc17odzOe2Ehf4DVrWddu3U4Ux3GFpOZHtc";
34//!
35//! let expected_claims = ClaimsSet::<PrivateClaims> {
36//!     registered: RegisteredClaims {
37//!         issuer: Some("https://www.acme.com/".into()),
38//!         subject: Some("John Doe".to_string()),
39//!         audience: Some("https://acme-customer.com/".into()),
40//!         not_before: Some(1234.try_into().unwrap()),
41//!         ..Default::default()
42//!     },
43//!     private: PrivateClaims {
44//!         department: "Toilet Cleaning".to_string(),
45//!         company: "ACME".to_string(),
46//!     },
47//! };
48//!
49//! let jwt = JWT::new(expected_claims.clone());
50//!
51//! let jws_token = jwt.encode::<sign::HS256>(&signing_key).unwrap();
52//! assert_eq!(expected_token, jws_token.to_string());
53//!
54//! // Encrypt the token
55//!
56//! // You would usually have your own AES key for this, but we will use a zeroed key as an example
57//! let key = jwk::OctetKey::new(vec![0; 256 / 8]);
58//!
59//! /// We need to create a nonce for AES GCM encryption.
60//! /// You must take care NOT to reuse the nonce.
61//! /// You can simply treat the nonce as a 96 bit
62//! /// counter that is incremented after every use
63//! ///
64//! /// In this case, we're using a 64bit counter + a 32bit random prefix tag
65//! fn generate_nonce() -> [u8; 96/8] {
66//!     # use std::sync::atomic::{AtomicU64, Ordering};
67//!     static NONCE: AtomicU64 = AtomicU64::new(0);
68//!     // use some lazy random generation so each service has a separate tag
69//!     static TAG: u32 = 0xDEADCAFE;
70//!
71//!     // fetch and increment the nonce counter
72//!     let nonce = NONCE.fetch_add(1, Ordering::Release);
73//!
74//!     // collect the bytes together and return them
75//!     let mut output = [0; 96/8];
76//!     output[0..32/8].copy_from_slice(&TAG.to_be_bytes());
77//!     output[32/8..].copy_from_slice(&nonce.to_be_bytes());
78//!     output
79//! }
80//! let nonce = generate_nonce();
81//!
82//! // Construct the JWE
83//! let jwe = JWE::new(jws_token.clone());
84//!
85//! // Encrypt
86//! let encrypted_jwe = jwe.encrypt::<
87//!     cea::A256GCM,   // encrypt the contents with AES256 GCM
88//!     kma::A256GCMKW, // perform key wrapping with AES256 GCM
89//! >(&key, nonce).unwrap();
90//!
91//! let jwe_token = encrypted_jwe.to_string();
92//!
93//! // Now, send `token` to your clients
94//!
95//! // ... some time later, we get token back!
96//! let encrypted_jwe: Encrypted<kma::A256GCMKW> = jwe_token.parse().unwrap();
97//!
98//! // Decrypt
99//! let decrypted_jwe: JWE<_> = encrypted_jwe.decrypt::<_, cea::A256GCM>(&key).unwrap();
100//!
101//! // Verify the JWT signature
102//! let decoded_jwt = decrypted_jwe.payload.verify::<sign::HS256>(&signing_key).unwrap();
103//!
104//! assert_eq!(decoded_jwt.payload, expected_claims);
105//! ```
106
107// ### RFCs
108// - [JSON Web Tokens RFC](https://tools.ietf.org/html/rfc7519)
109// - [JSON Web Signature RFC](https://tools.ietf.org/html/rfc7515)
110// - [JSON Web Algorithms RFC](https://tools.ietf.org/html/rfc7518)
111// - [JSON Web Encryption RFC](https://tools.ietf.org/html/rfc7516)
112// - [JSON Web Signature (JWS) Unencoded Payload Option](https://tools.ietf.org/html/rfc7797)
113// - [CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JOSE](https://tools.ietf.org/html/rfc8037)
114// - [JWS Unencoded Payload Option](https://tools.ietf.org/html/rfc7797)
115// - [JWK Thumbprint](https://tools.ietf.org/html/rfc7638)
116
117#![warn(clippy::pedantic)]
118#![allow(
119    clippy::module_name_repetitions,
120    clippy::missing_errors_doc,
121    clippy::missing_panics_doc,
122    clippy::must_use_candidate,
123    clippy::default_trait_access,
124    clippy::similar_names,
125    clippy::enum_glob_use
126)]
127
128use std::borrow::Cow;
129use std::fmt::Debug;
130use std::ops::Deref;
131
132use serde::de::DeserializeOwned;
133use serde::{Deserialize, Deserializer, Serialize, Serializer};
134use time::{Duration, OffsetDateTime};
135
136mod helpers;
137pub use crate::helpers::*;
138
139#[cfg(test)]
140#[macro_use]
141mod test;
142
143#[macro_use]
144mod serde_custom;
145
146#[macro_use]
147mod macros;
148
149pub mod errors;
150pub mod jwa;
151pub mod jwe;
152pub mod jwk;
153pub mod jws;
154
155use crate::errors::{Error, ValidationError};
156
157/// A trait to describe how to parse components of a compact form JWS or JWE
158pub trait FromCompactPart: Sized {
159    /// Try and parse raw bytes into Self
160    fn from_bytes(b: &[u8]) -> Result<Self, Error>;
161}
162
163/// A trait to describe how to produce components of a compact form JWS or JWE
164pub trait ToCompactPart: Sized {
165    /// Convert self into raw bytes
166    fn to_bytes(&self) -> Result<Cow<'_, [u8]>, Error>;
167}
168
169/// A [`CompactPart`] type that parses data as json using [`serde_json`]
170pub struct Json<T>(pub T);
171
172impl<T: DeserializeOwned> FromCompactPart for Json<T> {
173    fn from_bytes(b: &[u8]) -> Result<Self, Error> {
174        Ok(Json(serde_json::from_slice(b)?))
175    }
176}
177impl<T: Serialize> ToCompactPart for Json<T> {
178    fn to_bytes(&self) -> Result<Cow<'_, [u8]>, Error> {
179        Ok(serde_json::to_vec(&self.0)?.into())
180    }
181}
182
183impl FromCompactPart for Vec<u8> {
184    fn from_bytes(b: &[u8]) -> Result<Self, Error> {
185        Ok(b.to_vec())
186    }
187}
188impl ToCompactPart for Vec<u8> {
189    fn to_bytes(&self) -> Result<Cow<'_, [u8]>, Error> {
190        Ok(self.as_slice().into())
191    }
192}
193
194impl FromCompactPart for () {
195    fn from_bytes(b: &[u8]) -> Result<Self, Error> {
196        if b.is_empty() {
197            Ok(())
198        } else {
199            Err(Error::DecodeError(errors::DecodeError::PartsLengthError {
200                expected: 0,
201                actual: b.len(),
202            }))
203        }
204    }
205}
206impl ToCompactPart for () {
207    fn to_bytes(&self) -> Result<Cow<'_, [u8]>, Error> {
208        Ok(Cow::Borrowed(&[]))
209    }
210}
211
212/// A convenience type alias of a JSON Web Encryption token in it's decoded form. It
213/// contains a [`ClaimsSet`] as it's contents
214///
215/// Type `T` is the type of private claims for the JWT.
216///
217/// # Examples
218/// ## Encoding and decoding with HS256
219///
220/// ```
221/// use no_way::{JWT, jwa, jws, jwk, ClaimsSet, RegisteredClaims};
222/// use serde::{Serialize, Deserialize};
223///
224/// // Define our own private claims
225/// #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
226/// struct PrivateClaims {
227///     company: String,
228///     department: String,
229/// }
230///
231/// let signing_key = jwk::OctetKey::new("secret".to_string().into_bytes());
232///
233/// let expected_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\
234///        eyJpc3MiOiJodHRwczovL3d3dy5hY21lLmNvbS8iLCJzdWIiOiJKb2huIERvZSIsImF1ZCI6Imh0dHBzOi8vYWNtZ\
235///        S1jdXN0b21lci5jb20vIiwibmJmIjoxMjM0LCJjb21wYW55IjoiQUNNRSIsImRlcGFydG1lbnQiOiJUb2lsZXQgQ2\
236///        xlYW5pbmcifQ.VFCl2un1Kc17odzOe2Ehf4DVrWddu3U4Ux3GFpOZHtc";
237///
238/// let expected_claims = ClaimsSet::<PrivateClaims> {
239///     registered: RegisteredClaims {
240///         issuer: Some("https://www.acme.com/".into()),
241///         subject: Some("John Doe".to_string()),
242///         audience: Some("https://acme-customer.com/".into()),
243///         not_before: Some(1234.try_into().unwrap()),
244///         ..Default::default()
245///     },
246///     private: PrivateClaims {
247///         department: "Toilet Cleaning".to_string(),
248///         company: "ACME".to_string(),
249///     },
250/// };
251///
252/// let jwt = JWT::new(expected_claims.clone());
253///
254/// let token = jwt.encode::<jwa::sign::HS256>(&signing_key).unwrap().to_string();
255/// assert_eq!(expected_token, token);
256/// // Now, send `token` to your clients
257///
258/// // ... some time later, we get token back!
259///
260/// let encoded_token: jws::Unverified<_> = token.parse().unwrap();
261/// let token: JWT<_> = encoded_token.verify::<jwa::sign::HS256>(&signing_key).unwrap();
262/// assert_eq!(token.payload, expected_claims);
263/// ```
264pub type JWT<T> = jws::Verified<ClaimsSet<T>, ()>;
265
266/// A convenience type alias of a JSON Web Encryption token in it's decrypted form. It contains
267/// an encoded JWT<T> as it's contents.
268///
269/// Type `T` is the type of private claims for the JWT.
270///
271/// # Examples
272/// ## Sign with HS256, then encrypt with A256GCMKW and A256GCM
273///
274/// ```rust
275/// use no_way::{ClaimsSet, RegisteredClaims, JWT, JWE};
276/// use no_way::jwk;
277/// use no_way::jwe::Encrypted;
278/// use no_way::jwa::{kma, cea, sign};
279/// use serde::{Serialize, Deserialize};
280///
281/// // Define our own private claims
282/// #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
283/// struct PrivateClaims {
284///     company: String,
285///     department: String,
286/// }
287///
288/// // Craft our JWS
289/// let expected_claims = ClaimsSet::<PrivateClaims> {
290///     registered: RegisteredClaims {
291///         issuer: Some("https://www.acme.com".into()),
292///         subject: Some("John Doe".into()),
293///         audience: Some("htts://acme-customer.com".into()),
294///         not_before: Some(1234.try_into().unwrap()),
295///         ..Default::default()
296///     },
297///     private: PrivateClaims {
298///         department: "Toilet Cleaning".to_string(),
299///         company: "ACME".to_string(),
300///     },
301/// };
302///
303/// let expected_jwt = JWT::new(expected_claims.clone());
304///
305/// let signing_key = jwk::OctetKey::new("secret".to_string().into_bytes());
306/// let jws = expected_jwt.encode::<sign::HS256>(&signing_key).unwrap();
307///
308/// // Encrypt the token
309///
310/// // You would usually have your own AES key for this, but we will use a zeroed key as an example
311/// let key = jwk::OctetKey::new(vec![0; 256 / 8]);
312///
313/// /// We need to create a nonce for AES GCM encryption.
314/// /// You must take care NOT to reuse the nonce.
315/// /// You can simply treat the nonce as a 96 bit
316/// /// counter that is incremented after every use
317/// ///
318/// /// In this case, we're using a 64bit counter + a 32bit random prefix tag
319/// fn generate_nonce() -> [u8; 96/8] {
320///     # use std::sync::atomic::{AtomicU64, Ordering};
321///     static NONCE: AtomicU64 = AtomicU64::new(0);
322///     // use some lazy random generation so each service has a separate tag
323///     static TAG: u32 = 0xDEADCAFE;
324///
325///     // fetch and increment the nonce counter
326///     let nonce = NONCE.fetch_add(1, Ordering::Release);
327///
328///     // collect the bytes together and return them
329///     let mut output = [0; 96/8];
330///     output[0..32/8].copy_from_slice(&TAG.to_be_bytes());
331///     output[32/8..].copy_from_slice(&nonce.to_be_bytes());
332///     output
333/// }
334/// let nonce = generate_nonce();
335///
336/// // Construct the JWE
337/// let jwe = JWE::new(jws.clone());
338///
339/// // Encrypt
340/// let encrypted_jwe = jwe.encrypt::<
341///     cea::A256GCM,   // encrypt the contents with AES256 GCM
342///     kma::A256GCMKW, // perform key wrapping with AES256 GCM
343/// >(&key, nonce).unwrap();
344///
345/// let token = encrypted_jwe.to_string();
346///
347/// // Now, send `token` to your clients
348///
349/// // ... some time later, we get token back!
350/// let token: Encrypted<kma::A256GCMKW> = token.parse().unwrap();
351///
352/// // Decrypt
353/// let decrypted_jwe = token.decrypt::<_, cea::A256GCM>(&key).unwrap();
354///
355/// assert_eq!(jws, decrypted_jwe.payload);
356/// ```
357pub type JWE<T> = jwe::Decrypted<jws::Unverified<ClaimsSet<T>>, ()>;
358
359/// Represents a choice between a single value or multiple string values.
360///
361/// # Examples
362/// ```
363/// # use no_way::SingleOrMultiple;
364/// let single: SingleOrMultiple = "foobar".into();
365/// let expected_json = r#""foobar""#;
366///
367/// let serialized = serde_json::to_string(&single).unwrap();
368/// assert_eq!(expected_json, serialized);
369///
370/// let deserialized: SingleOrMultiple = serde_json::from_str(&serialized).unwrap();
371/// assert_eq!(deserialized, single);
372///
373/// let multiple: SingleOrMultiple = ["foo", "bar", "baz"].as_slice().into();
374/// let expected_json = r#"["foo","bar","baz"]"#;
375///
376/// let serialized = serde_json::to_string(&multiple).unwrap();
377/// assert_eq!(expected_json, serialized);
378///
379/// let deserialized: SingleOrMultiple = serde_json::from_str(&serialized).unwrap();
380/// assert_eq!(deserialized, multiple);
381/// ```
382#[derive(Clone, Debug, Eq, PartialEq)]
383pub enum SingleOrMultiple {
384    /// One single value
385    Single([String; 1]),
386    /// Multiple values
387    Multiple(Vec<String>),
388}
389
390mod serde_impls {
391    use super::SingleOrMultiple;
392
393    impl serde::Serialize for SingleOrMultiple {
394        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
395        where
396            S: serde::Serializer,
397        {
398            match self {
399                SingleOrMultiple::Single([field]) => field.serialize(serializer),
400                SingleOrMultiple::Multiple(ref field) => field.serialize(serializer),
401            }
402        }
403    }
404
405    struct Visitor;
406    impl<'de> serde::de::Visitor<'de> for Visitor {
407        type Value = SingleOrMultiple;
408        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
409            formatter.write_str("single or multiple strings")
410        }
411
412        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
413        where
414            E: serde::de::Error,
415        {
416            Ok(v.into())
417        }
418
419        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
420        where
421            E: serde::de::Error,
422        {
423            Ok(v.into())
424        }
425
426        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
427        where
428            A: serde::de::SeqAccess<'de>,
429        {
430            let mut values = Vec::new();
431            while let Some(value) = seq.next_element()? {
432                values.push(value);
433            }
434            Ok(SingleOrMultiple::Multiple(values))
435        }
436    }
437    impl<'de> serde::Deserialize<'de> for SingleOrMultiple {
438        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
439        where
440            D: serde::Deserializer<'de>,
441        {
442            deserializer.deserialize_any(Visitor)
443        }
444    }
445}
446
447impl From<&str> for SingleOrMultiple {
448    fn from(t: &str) -> Self {
449        Self::Single([t.to_owned()])
450    }
451}
452impl From<&[&str]> for SingleOrMultiple {
453    fn from(t: &[&str]) -> Self {
454        Self::Multiple(t.iter().map(|&s| s.to_owned()).collect())
455    }
456}
457impl From<String> for SingleOrMultiple {
458    fn from(t: String) -> Self {
459        Self::Single([t])
460    }
461}
462impl From<Vec<String>> for SingleOrMultiple {
463    fn from(t: Vec<String>) -> Self {
464        Self::Multiple(t)
465    }
466}
467
468impl SingleOrMultiple {
469    /// Checks whether this enum, regardless of single or multiple value contains `value`.
470    pub fn contains(&self, value: &str) -> bool {
471        match self {
472            Self::Single([single]) => single == value,
473            Self::Multiple(vector) => vector.iter().any(|v| v == value),
474        }
475    }
476
477    /// Yields an iterator for the single value or the list
478    pub fn iter(&self) -> std::slice::Iter<String> {
479        match self {
480            Self::Single(single) => single.iter(),
481            Self::Multiple(vector) => vector.iter(),
482        }
483    }
484}
485
486/// Wrapper around `OffsetDateTime` to allow us to do custom de(serialization)
487#[derive(Clone, Copy, Debug, Eq, PartialEq)]
488pub struct Timestamp(OffsetDateTime);
489
490impl Deref for Timestamp {
491    type Target = OffsetDateTime;
492    fn deref(&self) -> &Self::Target {
493        &self.0
494    }
495}
496
497impl From<OffsetDateTime> for Timestamp {
498    fn from(datetime: OffsetDateTime) -> Self {
499        Timestamp(datetime)
500    }
501}
502
503impl From<Timestamp> for OffsetDateTime {
504    fn from(ts: Timestamp) -> Self {
505        ts.0
506    }
507}
508
509impl TryFrom<i64> for Timestamp {
510    type Error = time::error::ComponentRange;
511
512    fn try_from(value: i64) -> Result<Self, Self::Error> {
513        OffsetDateTime::from_unix_timestamp(value).map(Self)
514    }
515}
516
517impl Serialize for Timestamp {
518    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
519    where
520        S: Serializer,
521    {
522        time::serde::timestamp::serialize(&self.0, serializer)
523    }
524}
525
526impl<'de> Deserialize<'de> for Timestamp {
527    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
528    where
529        D: Deserializer<'de>,
530    {
531        time::serde::timestamp::deserialize(deserializer).map(Self)
532    }
533}
534
535/// Registered claims defined by [RFC7519#4.1](https://tools.ietf.org/html/rfc7519#section-4.1)
536#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
537pub struct RegisteredClaims {
538    /// Token issuer. Serialized to `iss`.
539    #[serde(rename = "iss", skip_serializing_if = "Option::is_none")]
540    pub issuer: Option<String>,
541
542    /// Subject where the JWT is referring to. Serialized to `sub`
543    #[serde(rename = "sub", skip_serializing_if = "Option::is_none")]
544    pub subject: Option<String>,
545
546    /// Audience intended for the JWT. Serialized to `aud`
547    #[serde(rename = "aud", skip_serializing_if = "Option::is_none")]
548    pub audience: Option<SingleOrMultiple>,
549
550    /// Expiration time in seconds since Unix Epoch. Serialized to `exp`
551    #[serde(rename = "exp", skip_serializing_if = "Option::is_none")]
552    pub expiry: Option<Timestamp>,
553
554    /// Not before time in seconds since Unix Epoch. Serialized to `nbf`
555    #[serde(rename = "nbf", skip_serializing_if = "Option::is_none")]
556    pub not_before: Option<Timestamp>,
557
558    /// Issued at Time in seconds since Unix Epoch. Serialized to `iat`
559    #[serde(rename = "iat", skip_serializing_if = "Option::is_none")]
560    pub issued_at: Option<Timestamp>,
561
562    /// Application specific JWT ID. Serialized to `jti`
563    #[serde(rename = "jti", skip_serializing_if = "Option::is_none")]
564    pub id: Option<String>,
565}
566
567#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)]
568/// Options for claims presence validation
569///
570/// By default, no claims (namely `iat`, `exp`, `nbf`, `iss`, `aud`)
571/// are required, and they pass validation if they are missing.
572pub struct ClaimPresenceOptions {
573    /// Whether the `iat` or `Issued At` field is required
574    pub issued_at: Presence,
575    /// Whether the `nbf` or `Not Before` field is required
576    pub not_before: Presence,
577    /// Whether the `exp` or `Expiry` field is required
578    pub expiry: Presence,
579    /// Whether the `iss` or `Issuer` field is required
580    pub issuer: Presence,
581    /// Whether the `aud` or `Audience` field is required
582    pub audience: Presence,
583    /// Whether the `sub` or `Subject` field is required
584    pub subject: Presence,
585    /// Whether the `jti` or `JWT ID` field is required
586    pub id: Presence,
587}
588
589impl ClaimPresenceOptions {
590    /// Returns a `ClaimPresenceOptions` where every claim is required as per [RFC7523](https://tools.ietf.org/html/rfc7523#section-3)
591    pub fn strict() -> Self {
592        use Presence::Required;
593        ClaimPresenceOptions {
594            issued_at: Required,
595            not_before: Required,
596            expiry: Required,
597            issuer: Required,
598            audience: Required,
599            subject: Required,
600            id: Required,
601        }
602    }
603}
604
605#[derive(Eq, PartialEq, Clone)]
606/// Options for claims validation
607///
608/// If a claim is missing, it passes validation unless the claim is marked as required within the
609/// `claim_presence_options`.
610///
611/// By default, no claims are required. If there are present, only expiry-related claims are validated
612/// (namely `exp`, `nbf`, `iat`) with zero epsilon and maximum age duration.
613///
614/// Should any temporal claims be required, set the appropriate fields.
615///
616/// To deal with clock drifts, you might want to provide an `epsilon` error margin in the form of a
617/// `std::time::Duration` to allow time comparisons to fall within the margin.
618pub struct ValidationOptions {
619    /// Claims marked as required will trigger a validation failure if they are missing
620    pub claim_presence_options: ClaimPresenceOptions,
621
622    /// Define how to validate temporal claims
623    pub temporal_options: TemporalOptions,
624
625    /// Validation options for `iat` or `Issued At` claim if present
626    /// Parameter shows the maximum age of a token to be accepted,
627    /// use [```Duration::max_value()```] if you do not want to skip validating
628    /// the age of the token, and only validate it was not issued in the future
629    pub issued_at: Validation<Duration>,
630    /// Validation options for `nbf` or `Not Before` claim if present
631    pub not_before: Validation<()>,
632    /// Validation options for `exp` or `Expiry` claim if present
633    pub expiry: Validation<()>,
634
635    /// Validation options for `iss` or `Issuer` claim if present
636    /// Parameter must match the issuer in the token exactly.
637    pub issuer: Validation<String>,
638
639    /// Validation options for `aud` or `Audience` claim if present
640    /// Token must include an audience with the value of the parameter
641    pub audience: Validation<String>,
642}
643
644impl Default for ValidationOptions {
645    fn default() -> Self {
646        ValidationOptions {
647            expiry: Validation::Validate(()),
648            not_before: Validation::Validate(()),
649            issued_at: Validation::Validate(Duration::MAX),
650
651            claim_presence_options: Default::default(),
652            temporal_options: Default::default(),
653            audience: Default::default(),
654            issuer: Default::default(),
655        }
656    }
657}
658
659impl RegisteredClaims {
660    /// Validates that the token contains the claims defined as required
661    pub fn validate_claim_presence(
662        &self,
663        options: ClaimPresenceOptions,
664    ) -> Result<(), ValidationError> {
665        use crate::Presence::Required;
666
667        let mut missing_claims: Vec<&str> = vec![];
668
669        if options.expiry == Required && self.expiry.is_none() {
670            missing_claims.push("exp");
671        }
672
673        if options.not_before == Required && self.not_before.is_none() {
674            missing_claims.push("nbf");
675        }
676
677        if options.issued_at == Required && self.issued_at.is_none() {
678            missing_claims.push("iat");
679        }
680
681        if options.audience == Required && self.audience.is_none() {
682            missing_claims.push("aud");
683        }
684
685        if options.issuer == Required && self.issuer.is_none() {
686            missing_claims.push("iss");
687        }
688
689        if options.subject == Required && self.subject.is_none() {
690            missing_claims.push("sub");
691        }
692
693        if options.id == Required && self.id.is_none() {
694            missing_claims.push("jti");
695        }
696
697        if missing_claims.is_empty() {
698            Ok(())
699        } else {
700            Err(ValidationError::MissingRequiredClaims(
701                missing_claims.into_iter().map(Into::into).collect(),
702            ))
703        }
704    }
705
706    /// Validates that if the token has an `exp` claim, it has not passed.
707    pub fn validate_exp(
708        &self,
709        validation: Validation<TemporalOptions>,
710    ) -> Result<(), ValidationError> {
711        match validation {
712            Validation::Ignored => Ok(()),
713            Validation::Validate(temporal_options) => {
714                let now = temporal_options.now.unwrap_or_else(OffsetDateTime::now_utc);
715
716                match self.expiry {
717                    Some(Timestamp(expiry)) if now - expiry > temporal_options.epsilon => {
718                        Err(ValidationError::Expired(now - expiry))
719                    }
720                    _ => Ok(()),
721                }
722            }
723        }
724    }
725
726    /// Validates that if the token has an `nbf` claim, it has passed.
727    pub fn validate_nbf(
728        &self,
729        validation: Validation<TemporalOptions>,
730    ) -> Result<(), ValidationError> {
731        match validation {
732            Validation::Ignored => Ok(()),
733            Validation::Validate(temporal_options) => {
734                let now = temporal_options.now.unwrap_or_else(OffsetDateTime::now_utc);
735
736                match self.not_before {
737                    Some(Timestamp(nbf)) if nbf - now > temporal_options.epsilon => {
738                        Err(ValidationError::NotYetValid(nbf - now))
739                    }
740                    _ => Ok(()),
741                }
742            }
743        }
744    }
745
746    /// Validates that if the token has an `iat` claim, it is not in the future and not older than the Duration
747    pub fn validate_iat(
748        &self,
749        validation: Validation<(Duration, TemporalOptions)>,
750    ) -> Result<(), ValidationError> {
751        match validation {
752            Validation::Ignored => Ok(()),
753            Validation::Validate((max_age, temporal_options)) => {
754                let now = temporal_options.now.unwrap_or_else(OffsetDateTime::now_utc);
755
756                match self.issued_at {
757                    Some(Timestamp(iat)) if iat - now > temporal_options.epsilon => {
758                        Err(ValidationError::NotYetValid(iat - now))
759                    }
760                    Some(Timestamp(iat)) if now - iat > max_age - temporal_options.epsilon => {
761                        Err(ValidationError::TooOld(now - iat - max_age))
762                    }
763                    _ => Ok(()),
764                }
765            }
766        }
767    }
768
769    /// Validates that if the token has an `aud` claim, it contains an entry which matches the expected audience
770    pub fn validate_aud(&self, validation: Validation<String>) -> Result<(), ValidationError> {
771        match validation {
772            Validation::Ignored => Ok(()),
773            Validation::Validate(expected_aud) => match &self.audience {
774                Some(SingleOrMultiple::Single([audience])) if audience != &expected_aud => Err(
775                    ValidationError::InvalidAudience(SingleOrMultiple::Single([audience.clone()])),
776                ),
777                Some(SingleOrMultiple::Multiple(audiences))
778                    if !audiences.contains(&expected_aud) =>
779                {
780                    Err(ValidationError::InvalidAudience(
781                        SingleOrMultiple::Multiple(audiences.clone()),
782                    ))
783                }
784                _ => Ok(()),
785            },
786        }
787    }
788
789    /// Validates that if the token has an `iss` claim, it matches the expected issuer
790    pub fn validate_iss(&self, validation: Validation<String>) -> Result<(), ValidationError> {
791        match validation {
792            Validation::Ignored => Ok(()),
793            Validation::Validate(expected_issuer) => match self.issuer {
794                Some(ref iss) if iss != &expected_issuer => {
795                    Err(ValidationError::InvalidIssuer(iss.clone()))
796                }
797                _ => Ok(()),
798            },
799        }
800    }
801
802    /// Performs full validation of the token according to the `ValidationOptions` supplied
803    ///
804    /// First it validates that all claims marked as required are present
805    /// Then it validates each claim marked to be validated if they are present in the token
806    /// (even those that are not marked as required, but are present).
807    pub fn validate(&self, options: ValidationOptions) -> Result<(), ValidationError> {
808        self.validate_claim_presence(options.claim_presence_options)?;
809        self.validate_exp(options.expiry.map(|_| options.temporal_options))?;
810        self.validate_nbf(options.not_before.map(|_| options.temporal_options))?;
811        self.validate_iat(options.issued_at.map(|dur| (dur, options.temporal_options)))?;
812
813        self.validate_iss(options.issuer)?;
814        self.validate_aud(options.audience)?;
815
816        //        self.validate_sub(options.subject_validated)?;
817        //        self.validate_custom(options.custom_validation)?;
818
819        Ok(())
820    }
821}
822
823/// A collection of claims, both [registered](https://tools.ietf.org/html/rfc7519#section-4.1) and your custom
824/// private claims.
825#[derive(Debug, Eq, PartialEq, Clone, Default, Serialize, Deserialize)]
826pub struct ClaimsSet<T> {
827    /// Registered claims defined by the RFC
828    #[serde(flatten)]
829    pub registered: RegisteredClaims,
830    /// Application specific claims
831    #[serde(flatten)]
832    pub private: T,
833}
834
835impl<T: DeserializeOwned> FromCompactPart for ClaimsSet<T> {
836    fn from_bytes(b: &[u8]) -> Result<Self, Error> {
837        Ok(serde_json::from_slice(b)?)
838    }
839}
840impl<T: Serialize> ToCompactPart for ClaimsSet<T> {
841    fn to_bytes(&self) -> Result<Cow<'_, [u8]>, Error> {
842        Ok(serde_json::to_vec(&self)?.into())
843    }
844}
845
846type B64 = base64ct::Base64UrlUnpadded;
847
848#[cfg(test)]
849mod tests {
850    use super::*;
851    use time::Duration;
852
853    #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
854    struct PrivateClaims {
855        company: String,
856        department: String,
857    }
858
859    // impl CompactJson for PrivateClaims {}
860
861    #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
862    struct InvalidPrivateClaim {
863        sub: String,
864        company: String,
865    }
866
867    #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
868    struct SingleOrMultipleStrings {
869        values: SingleOrMultiple,
870    }
871
872    #[test]
873    fn single_string_serialization_round_trip() {
874        let test = SingleOrMultipleStrings {
875            values: "foobar".into(),
876        };
877        let expected_json = r#"{"values":"foobar"}"#;
878
879        let serialized = serde_json::to_string(&test).unwrap();
880        assert_eq!(expected_json, serialized);
881
882        let deserialized: SingleOrMultipleStrings = serde_json::from_str(&serialized).unwrap();
883        assert_eq!(deserialized, test);
884        assert!(deserialized.values.contains("foobar"));
885        assert!(!deserialized.values.contains("does not exist"));
886    }
887
888    #[test]
889    fn multiple_strings_serialization_round_trip() {
890        let test = SingleOrMultipleStrings {
891            values: ["foo", "bar", "baz"].as_slice().into(),
892        };
893        let expected_json = r#"{"values":["foo","bar","baz"]}"#;
894
895        let serialized = serde_json::to_string(&test).unwrap();
896        assert_eq!(expected_json, serialized);
897
898        let deserialized: SingleOrMultipleStrings = serde_json::from_str(&serialized).unwrap();
899        assert_eq!(deserialized, test);
900        assert!(deserialized.values.contains("foo"));
901        assert!(deserialized.values.contains("bar"));
902        assert!(deserialized.values.contains("baz"));
903        assert!(!deserialized.values.contains("does not exist"));
904    }
905
906    #[test]
907    fn single_string_or_uri_string_serialization_round_trip() {
908        let test = SingleOrMultipleStrings {
909            values: "foobar".into(),
910        };
911        let expected_json = r#"{"values":"foobar"}"#;
912
913        let serialized = serde_json::to_string(&test).unwrap();
914        assert_eq!(expected_json, serialized);
915
916        let deserialized: SingleOrMultipleStrings = serde_json::from_str(&serialized).unwrap();
917        assert_eq!(deserialized, test);
918        assert!(deserialized.values.contains("foobar"));
919        assert!(!deserialized.values.contains("does not exist"));
920    }
921
922    #[test]
923    fn single_string_or_uri_uri_serialization_round_trip() {
924        let test = SingleOrMultipleStrings {
925            values: "https://www.examples.com/".into(),
926        };
927        let expected_json = r#"{"values":"https://www.examples.com/"}"#;
928
929        let serialized = serde_json::to_string(&test).unwrap();
930        assert_eq!(expected_json, serialized);
931
932        let deserialized: SingleOrMultipleStrings = serde_json::from_str(&serialized).unwrap();
933        assert_eq!(deserialized, test);
934        assert!(deserialized.values.contains("https://www.examples.com/"));
935        assert!(!deserialized.values.contains("https://ecorp.com"));
936    }
937
938    #[test]
939    fn multiple_string_or_uri_serialization_round_trip() {
940        let test = SingleOrMultipleStrings {
941            values: [
942                "foo",
943                "https://www.example.com/",
944                "data:text/plain,Hello?World#",
945                "http://[::1]/",
946                "baz",
947            ]
948            .as_slice()
949            .into(),
950        };
951        let expected_json = r#"{"values":["foo","https://www.example.com/","data:text/plain,Hello?World#","http://[::1]/","baz"]}"#;
952
953        let serialized = serde_json::to_string(&test).unwrap();
954        assert_eq!(expected_json, serialized);
955
956        let deserialized: SingleOrMultipleStrings = serde_json::from_str(&serialized).unwrap();
957        assert_eq!(deserialized, test);
958
959        assert!(deserialized.values.contains("foo"));
960        assert!(deserialized.values.contains("https://www.example.com/"));
961        assert!(deserialized.values.contains("data:text/plain,Hello?World#"));
962        assert!(deserialized.values.contains("http://[::1]/"));
963        assert!(deserialized.values.contains("baz"));
964        assert!(!deserialized.values.contains("https://ecorp.com"));
965    }
966
967    #[test]
968    fn timestamp_serialization_roundtrip() {
969        let now: Timestamp = OffsetDateTime::now_utc()
970            .replace_nanosecond(0)
971            .unwrap()
972            .into();
973        let serialized = serde_json::to_string(&now).unwrap();
974        let deserialized = serde_json::from_str(&serialized).unwrap();
975        assert_eq!(now, deserialized);
976
977        let fixed_time: Timestamp = 1000.try_into().unwrap();
978        let serialized = serde_json::to_string(&fixed_time).unwrap();
979        assert_eq!(serialized, "1000");
980        let deserialized = serde_json::from_str(&serialized).unwrap();
981        assert_eq!(fixed_time, deserialized);
982    }
983
984    #[test]
985    fn empty_registered_claims_serialization_round_trip() {
986        let claim = RegisteredClaims::default();
987        let expected_json = "{}";
988
989        let serialized = serde_json::to_string(&claim).unwrap();
990        assert_eq!(expected_json, serialized);
991
992        let deserialized: RegisteredClaims = serde_json::from_str(&serialized).unwrap();
993        assert_eq!(deserialized, claim);
994    }
995
996    #[test]
997    fn registered_claims_serialization_round_trip() {
998        let claim = RegisteredClaims {
999            issuer: Some("https://www.acme.com/".into()),
1000            audience: Some("htts://acme-customer.com/".into()),
1001            not_before: Some(1234.try_into().unwrap()),
1002            ..Default::default()
1003        };
1004        let expected_json =
1005            r#"{"iss":"https://www.acme.com/","aud":"htts://acme-customer.com/","nbf":1234}"#;
1006
1007        let serialized = serde_json::to_string(&claim).unwrap();
1008        assert_eq!(expected_json, serialized);
1009
1010        let deserialized: RegisteredClaims = serde_json::from_str(&serialized).unwrap();
1011        assert_eq!(deserialized, claim);
1012    }
1013
1014    #[test]
1015    fn claims_set_serialization_round_trip() {
1016        let claim = ClaimsSet::<PrivateClaims> {
1017            registered: RegisteredClaims {
1018                issuer: Some("https://www.acme.com/".into()),
1019                subject: Some("John Doe".into()),
1020                audience: Some("htts://acme-customer.com/".into()),
1021                not_before: Some(1234.try_into().unwrap()),
1022                ..Default::default()
1023            },
1024            private: PrivateClaims {
1025                department: "Toilet Cleaning".to_string(),
1026                company: "ACME".to_string(),
1027            },
1028        };
1029
1030        let expected_json = "{\"iss\":\"https://www.acme.com/\",\"sub\":\"John Doe\",\
1031                             \"aud\":\"htts://acme-customer.com/\",\
1032                             \"nbf\":1234,\"company\":\"ACME\",\"department\":\"Toilet Cleaning\"}";
1033
1034        let serialized = serde_json::to_string(&claim).unwrap();
1035        assert_eq!(expected_json, serialized);
1036
1037        let deserialized: ClaimsSet<PrivateClaims> = serde_json::from_str(&serialized).unwrap();
1038        assert_eq!(deserialized, claim);
1039    }
1040
1041    #[test]
1042    // serde's flatten will serialize them twice
1043    fn duplicate_claims_round_trip() {
1044        let claim = ClaimsSet::<InvalidPrivateClaim> {
1045            registered: RegisteredClaims {
1046                issuer: Some("https://www.acme.com".into()),
1047                subject: Some("John Doe".into()),
1048                audience: Some("htts://acme-customer.com".into()),
1049                not_before: Some(1234.try_into().unwrap()),
1050                ..Default::default()
1051            },
1052            private: InvalidPrivateClaim {
1053                sub: "John Doe".to_string(),
1054                company: "ACME".to_string(),
1055            },
1056        };
1057
1058        let json = serde_json::to_string(&claim).unwrap();
1059        assert_eq!(2, json.matches("\"sub\"").count());
1060
1061        let duplicate: Result<ClaimsSet<InvalidPrivateClaim>, _> = serde_json::from_str(&json);
1062        assert!(duplicate.is_err());
1063        let error = duplicate.unwrap_err().to_string();
1064        assert!(error.contains("duplicate field `sub`"));
1065    }
1066
1067    #[test]
1068    #[should_panic(expected = "MissingRequiredClaims([\"iat\"])")]
1069    fn validate_times_missing_iat() {
1070        let registered_claims = RegisteredClaims::default();
1071        let options = ClaimPresenceOptions {
1072            issued_at: Presence::Required,
1073            ..Default::default()
1074        };
1075        registered_claims.validate_claim_presence(options).unwrap();
1076    }
1077
1078    #[test]
1079    #[should_panic(expected = "MissingRequiredClaims([\"exp\"])")]
1080    fn validate_times_missing_exp() {
1081        let registered_claims = RegisteredClaims::default();
1082        let options = ClaimPresenceOptions {
1083            expiry: Presence::Required,
1084            ..Default::default()
1085        };
1086        registered_claims.validate_claim_presence(options).unwrap();
1087    }
1088
1089    #[test]
1090    #[should_panic(expected = "MissingRequiredClaims([\"nbf\"])")]
1091    fn validate_times_missing_nbf() {
1092        let registered_claims = RegisteredClaims::default();
1093        let options = ClaimPresenceOptions {
1094            not_before: Presence::Required,
1095            ..Default::default()
1096        };
1097        registered_claims.validate_claim_presence(options).unwrap();
1098    }
1099
1100    #[test]
1101    #[should_panic(expected = "MissingRequiredClaims([\"aud\"])")]
1102    fn validate_times_missing_aud() {
1103        let registered_claims = RegisteredClaims::default();
1104        let options = ClaimPresenceOptions {
1105            audience: Presence::Required,
1106            ..Default::default()
1107        };
1108        registered_claims.validate_claim_presence(options).unwrap();
1109    }
1110
1111    #[test]
1112    #[should_panic(expected = "MissingRequiredClaims([\"iss\"])")]
1113    fn validate_times_missing_iss() {
1114        let registered_claims = RegisteredClaims::default();
1115        let options = ClaimPresenceOptions {
1116            issuer: Presence::Required,
1117            ..Default::default()
1118        };
1119        registered_claims.validate_claim_presence(options).unwrap();
1120    }
1121
1122    #[test]
1123    #[should_panic(expected = "MissingRequiredClaims([\"sub\"])")]
1124    fn validate_times_missing_sub() {
1125        let registered_claims = RegisteredClaims::default();
1126        let options = ClaimPresenceOptions {
1127            subject: Presence::Required,
1128            ..Default::default()
1129        };
1130        registered_claims.validate_claim_presence(options).unwrap();
1131    }
1132
1133    #[test]
1134    #[should_panic(
1135        expected = "MissingRequiredClaims([\"exp\", \"nbf\", \"iat\", \"aud\", \"iss\", \"sub\", \"jti\"])"
1136    )]
1137    fn validate_times_missing_all() {
1138        let registered_claims = RegisteredClaims::default();
1139        let options = ClaimPresenceOptions::strict();
1140        registered_claims.validate_claim_presence(options).unwrap();
1141    }
1142
1143    #[test]
1144    fn validate_times_catch_future_token() {
1145        let temporal_options = TemporalOptions {
1146            now: Some(OffsetDateTime::from_unix_timestamp(0).unwrap()),
1147            ..Default::default()
1148        };
1149
1150        let registered_claims = RegisteredClaims {
1151            issued_at: Some(10.try_into().unwrap()),
1152            ..Default::default()
1153        };
1154
1155        assert_eq!(
1156            Err(ValidationError::NotYetValid(Duration::seconds(10))),
1157            registered_claims.validate_iat(Validation::Validate((
1158                Duration::seconds(0),
1159                temporal_options
1160            )))
1161        );
1162    }
1163
1164    #[test]
1165    fn validate_times_catch_too_old_token() {
1166        let temporal_options = TemporalOptions {
1167            now: Some(OffsetDateTime::from_unix_timestamp(40).unwrap()),
1168            ..Default::default()
1169        };
1170
1171        let registered_claims = RegisteredClaims {
1172            issued_at: Some(10.try_into().unwrap()),
1173            ..Default::default()
1174        };
1175
1176        assert_eq!(
1177            Err(ValidationError::TooOld(Duration::seconds(5))),
1178            registered_claims.validate_iat(Validation::Validate((
1179                Duration::seconds(25),
1180                temporal_options
1181            )))
1182        );
1183    }
1184
1185    #[test]
1186    fn validate_times_catch_expired_token() {
1187        let temporal_options = TemporalOptions {
1188            now: Some(OffsetDateTime::from_unix_timestamp(2).unwrap()),
1189            ..Default::default()
1190        };
1191
1192        let registered_claims = RegisteredClaims {
1193            expiry: Some(1.try_into().unwrap()),
1194            ..Default::default()
1195        };
1196
1197        assert_eq!(
1198            Err(ValidationError::Expired(Duration::seconds(1))),
1199            registered_claims.validate_exp(Validation::Validate(temporal_options))
1200        );
1201    }
1202
1203    #[test]
1204    fn validate_times_catch_early_token() {
1205        let temporal_options = TemporalOptions {
1206            now: Some(OffsetDateTime::from_unix_timestamp(0).unwrap()),
1207            ..Default::default()
1208        };
1209
1210        let registered_claims = RegisteredClaims {
1211            not_before: Some(1.try_into().unwrap()),
1212            ..Default::default()
1213        };
1214
1215        assert_eq!(
1216            Err(ValidationError::NotYetValid(Duration::seconds(1))),
1217            registered_claims.validate_nbf(Validation::Validate(temporal_options))
1218        );
1219    }
1220
1221    #[test]
1222    fn validate_times_valid_token_with_default_options() {
1223        let registered_claims = RegisteredClaims {
1224            not_before: Some(Timestamp(OffsetDateTime::now_utc() - Duration::days(2))),
1225            issued_at: Some(Timestamp(OffsetDateTime::now_utc() - Duration::days(1))),
1226            expiry: Some(Timestamp(OffsetDateTime::now_utc() + Duration::days(1))),
1227            ..Default::default()
1228        };
1229
1230        let validation_options = ValidationOptions {
1231            temporal_options: Default::default(),
1232            claim_presence_options: Default::default(),
1233
1234            expiry: Validation::Validate(()),
1235            not_before: Validation::Validate(()),
1236            issued_at: Validation::Validate(Duration::MAX),
1237
1238            ..Default::default()
1239        };
1240
1241        registered_claims.validate(validation_options).unwrap();
1242    }
1243
1244    #[test]
1245    fn validate_issuer_catch_mismatch() {
1246        let registered_claims = RegisteredClaims {
1247            issuer: Some("issuer".to_string()),
1248            ..Default::default()
1249        };
1250
1251        assert_eq!(
1252            Err(ValidationError::InvalidIssuer("issuer".to_string())),
1253            registered_claims.validate_iss(Validation::Validate("http://issuer".to_string()))
1254        );
1255    }
1256
1257    #[test]
1258    fn validate_audience_when_single() {
1259        let aud: SingleOrMultiple = "audience".into();
1260
1261        let registered_claims = RegisteredClaims {
1262            audience: Some(aud.clone()),
1263            ..Default::default()
1264        };
1265
1266        assert_eq!(
1267            Err(ValidationError::InvalidAudience(aud.clone())),
1268            registered_claims.validate_aud(Validation::Validate("http://audience".to_string()))
1269        );
1270
1271        assert_eq!(
1272            Err(ValidationError::InvalidAudience(aud)),
1273            registered_claims.validate_aud(Validation::Validate("audience2".to_string()))
1274        );
1275
1276        assert_eq!(
1277            Ok(()),
1278            registered_claims.validate_aud(Validation::Validate("audience".to_string()))
1279        );
1280    }
1281
1282    #[test]
1283    fn validate_audience_when_multiple() {
1284        let aud =
1285            SingleOrMultiple::Multiple(vec!["audience".to_string(), "http://audience".to_string()]);
1286
1287        let registered_claims = RegisteredClaims {
1288            audience: Some(aud.clone()),
1289            ..Default::default()
1290        };
1291
1292        assert_eq!(
1293            Ok(()),
1294            registered_claims.validate_aud(Validation::Validate("http://audience".to_string()))
1295        );
1296
1297        assert_eq!(
1298            Err(ValidationError::InvalidAudience(aud.clone())),
1299            registered_claims.validate_aud(Validation::Validate("audience2".to_string()))
1300        );
1301
1302        assert_eq!(
1303            Err(ValidationError::InvalidAudience(aud)),
1304            registered_claims.validate_aud(Validation::Validate("https://audience".to_string()))
1305        );
1306
1307        assert_eq!(
1308            Ok(()),
1309            registered_claims.validate_aud(Validation::Validate("audience".to_string()))
1310        );
1311    }
1312
1313    #[test]
1314    fn validate_valid_token_with_all_required() {
1315        let registered_claims = RegisteredClaims {
1316            expiry: Some(999.try_into().unwrap()),
1317            not_before: Some(1.try_into().unwrap()),
1318            issued_at: Some(95.try_into().unwrap()),
1319            subject: Some("subject".to_string()),
1320            issuer: Some("issuer".to_string()),
1321            audience: Some(SingleOrMultiple::Multiple(vec![
1322                "http://audience".to_string(),
1323                "audience".to_string(),
1324            ])),
1325            id: Some("id".into()),
1326        };
1327
1328        let temporal_options = TemporalOptions {
1329            now: Some(OffsetDateTime::from_unix_timestamp(100).unwrap()),
1330            ..Default::default()
1331        };
1332
1333        let validation_options = ValidationOptions {
1334            temporal_options,
1335            claim_presence_options: ClaimPresenceOptions::strict(),
1336
1337            expiry: Validation::Validate(()),
1338            not_before: Validation::Validate(()),
1339            issued_at: Validation::Validate(Duration::MAX),
1340            audience: Validation::Validate("audience".to_string()),
1341            issuer: Validation::Validate("issuer".to_string()),
1342        };
1343
1344        registered_claims.validate(validation_options).unwrap();
1345    }
1346
1347    #[test]
1348    fn validate_times_valid_token_with_epsilon() {
1349        let registered_claims = RegisteredClaims {
1350            expiry: Some(99.try_into().unwrap()),
1351            not_before: Some(96.try_into().unwrap()),
1352            issued_at: Some(96.try_into().unwrap()),
1353            ..Default::default()
1354        };
1355
1356        let temporal_options = TemporalOptions {
1357            now: Some(OffsetDateTime::from_unix_timestamp(100).unwrap()),
1358            epsilon: Duration::seconds(10),
1359        };
1360
1361        let validation_options = ValidationOptions {
1362            temporal_options,
1363            claim_presence_options: Default::default(),
1364
1365            expiry: Validation::Validate(()),
1366            not_before: Validation::Validate(()),
1367            issued_at: Validation::Validate(Duration::MAX),
1368
1369            ..Default::default()
1370        };
1371
1372        registered_claims.validate(validation_options).unwrap();
1373    }
1374}