Skip to main content

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}