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}