modo/auth/session/jwt/validation.rs
1use std::time::Duration;
2
3/// Policy-level validation rules applied to every `decode()` call.
4///
5/// `exp` is always enforced (not configurable). These fields control
6/// additional checks for `iss`, `aud`, and clock skew tolerance.
7///
8/// Built automatically from [`JwtSessionsConfig`](super::config::JwtSessionsConfig) by
9/// `JwtEncoder::from_config()` and `JwtDecoder::from_config()`.
10#[non_exhaustive]
11#[derive(Debug, Clone)]
12pub struct ValidationConfig {
13 /// Allowed clock skew applied to `exp` and `nbf` checks.
14 /// Defaults to `Duration::ZERO`.
15 pub leeway: Duration,
16 /// When `Some`, `decode()` rejects tokens whose `iss` does not match.
17 pub require_issuer: Option<String>,
18 /// When `Some`, `decode()` rejects tokens whose `aud` does not match.
19 pub require_audience: Option<String>,
20}
21
22impl Default for ValidationConfig {
23 fn default() -> Self {
24 Self {
25 leeway: Duration::ZERO,
26 require_issuer: None,
27 require_audience: None,
28 }
29 }
30}
31
32impl ValidationConfig {
33 /// Require that decoded tokens carry a specific `aud` claim.
34 ///
35 /// Returns a new `ValidationConfig` with `require_audience` set. All other
36 /// fields are unchanged.
37 ///
38 /// # Example
39 ///
40 /// ```rust,ignore
41 /// let validation = ValidationConfig::default().with_audience("my-app");
42 /// ```
43 #[must_use]
44 pub fn with_audience(mut self, aud: impl Into<String>) -> Self {
45 self.require_audience = Some(aud.into());
46 self
47 }
48
49 /// Require that decoded tokens carry a specific `iss` claim.
50 ///
51 /// Returns a new `ValidationConfig` with `require_issuer` set. All other
52 /// fields are unchanged.
53 #[must_use]
54 pub fn with_issuer(mut self, iss: impl Into<String>) -> Self {
55 self.require_issuer = Some(iss.into());
56 self
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn default_has_zero_leeway_and_no_requirements() {
66 let config = ValidationConfig::default();
67 assert_eq!(config.leeway, Duration::ZERO);
68 assert!(config.require_issuer.is_none());
69 assert!(config.require_audience.is_none());
70 }
71}