Skip to main content

modo/auth/session/cookie/
config.rs

1use serde::Deserialize;
2
3use crate::cookie::CookieConfig;
4
5fn deserialize_nonzero_usize<'de, D>(deserializer: D) -> Result<usize, D::Error>
6where
7    D: serde::Deserializer<'de>,
8{
9    let value = usize::deserialize(deserializer)?;
10    if value == 0 {
11        return Err(serde::de::Error::custom(
12            "max_sessions_per_user must be > 0; setting it to 0 would lock out all users",
13        ));
14    }
15    Ok(value)
16}
17
18/// Configuration for the cookie-backed session middleware.
19///
20/// Deserialised from the `session` key in the application YAML config.
21/// All fields have defaults, so an empty `session:` block is valid.
22///
23/// # YAML example
24///
25/// ```yaml
26/// session:
27///   session_ttl_secs: 2592000   # 30 days
28///   cookie_name: "_session"
29///   validate_fingerprint: true
30///   touch_interval_secs: 300    # 5 minutes
31///   max_sessions_per_user: 10
32///   cookie:
33///     secret: "your-secret-here"
34///     secure: true
35///     http_only: true
36///     same_site: "lax"
37/// ```
38#[non_exhaustive]
39#[derive(Debug, Clone, Deserialize)]
40#[serde(default)]
41pub struct CookieSessionsConfig {
42    /// Session lifetime in seconds. Defaults to `2_592_000` (30 days).
43    pub session_ttl_secs: u64,
44    /// Name of the session cookie. Defaults to `"_session"`.
45    pub cookie_name: String,
46    /// When `true`, the middleware rejects requests whose browser fingerprint
47    /// does not match the one recorded at login. Defaults to `true`.
48    pub validate_fingerprint: bool,
49    /// Minimum interval between `last_active_at` updates, in seconds.
50    /// A session is only touched when at least this many seconds have elapsed
51    /// since the last touch. Defaults to `300` (5 minutes).
52    pub touch_interval_secs: u64,
53    /// Maximum number of concurrent active sessions per user. When exceeded,
54    /// the least-recently-used session is evicted. Must be greater than zero.
55    /// Defaults to `10`.
56    #[serde(deserialize_with = "deserialize_nonzero_usize")]
57    pub max_sessions_per_user: usize,
58    /// Cookie security attributes (secret, secure flag, HttpOnly, SameSite).
59    pub cookie: CookieConfig,
60}
61
62impl Default for CookieSessionsConfig {
63    fn default() -> Self {
64        Self {
65            session_ttl_secs: 2_592_000,
66            cookie_name: "_session".to_string(),
67            validate_fingerprint: true,
68            touch_interval_secs: 300,
69            max_sessions_per_user: 10,
70            cookie: CookieConfig::default(),
71        }
72    }
73}