Skip to main content

rs_auth_core/
config.rs

1use time::Duration;
2
3/// Top-level authentication configuration.
4#[derive(Debug, Clone)]
5pub struct AuthConfig {
6    /// Secret used for cookie signing. Must be kept private.
7    pub secret: String,
8    /// Session time-to-live. Default: 30 days.
9    pub session_ttl: Duration,
10    /// Verification token time-to-live. Default: 1 hour.
11    pub verification_ttl: Duration,
12    /// Password reset token time-to-live. Default: 1 hour.
13    pub reset_ttl: Duration,
14    /// Length of generated tokens in bytes. Default: 32.
15    pub token_length: usize,
16    /// Email behavior configuration.
17    pub email: EmailConfig,
18    /// HTTP cookie configuration.
19    pub cookie: CookieConfig,
20    /// OAuth provider configuration.
21    pub oauth: OAuthConfig,
22}
23
24/// Email behavior configuration.
25#[derive(Debug, Clone)]
26pub struct EmailConfig {
27    /// Whether to send a verification email on signup. Default: true.
28    pub send_verification_on_signup: bool,
29    /// Whether to require email verification before allowing login. Default: false.
30    pub require_verification_to_login: bool,
31    /// Whether to automatically sign in the user after signup. Default: true.
32    pub auto_sign_in_after_signup: bool,
33    /// Whether to automatically sign in the user after email verification. Default: false.
34    pub auto_sign_in_after_verification: bool,
35}
36
37/// HTTP cookie configuration.
38#[derive(Debug, Clone)]
39pub struct CookieConfig {
40    /// Cookie name. Default: "rs_auth_session".
41    pub name: String,
42    /// Whether the cookie is HTTP-only. Default: true.
43    pub http_only: bool,
44    /// Whether the cookie requires HTTPS. Default: true.
45    pub secure: bool,
46    /// SameSite attribute. Default: Lax.
47    pub same_site: SameSite,
48    /// Cookie path. Default: "/".
49    pub path: String,
50    /// Cookie domain. Default: None.
51    pub domain: Option<String>,
52}
53
54/// SameSite cookie attribute.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum SameSite {
57    /// Strict SameSite policy.
58    Strict,
59    /// Lax SameSite policy.
60    Lax,
61    /// No SameSite policy.
62    None,
63}
64
65/// OAuth provider configuration.
66#[derive(Debug, Clone)]
67pub struct OAuthConfig {
68    /// List of configured OAuth providers.
69    pub providers: Vec<OAuthProviderEntry>,
70    /// Whether to allow implicit account linking when OAuth email matches existing user. Default: true.
71    pub allow_implicit_account_linking: bool,
72    /// URL to redirect to after successful OAuth login. Default: None.
73    pub success_redirect: Option<String>,
74    /// URL to redirect to after OAuth error. Default: None.
75    pub error_redirect: Option<String>,
76}
77
78/// OAuth provider entry.
79#[derive(Debug, Clone)]
80pub struct OAuthProviderEntry {
81    /// Provider identifier (e.g., "google", "github").
82    pub provider_id: String,
83    /// OAuth client ID.
84    pub client_id: String,
85    /// OAuth client secret. Must be kept private.
86    pub client_secret: String,
87    /// OAuth redirect URL.
88    pub redirect_url: String,
89    /// Override authorization URL, primarily useful for testing or self-hosted providers.
90    pub auth_url: Option<String>,
91    /// Override token URL, primarily useful for testing or self-hosted providers.
92    pub token_url: Option<String>,
93    /// Override userinfo URL, primarily useful for testing or self-hosted providers.
94    pub userinfo_url: Option<String>,
95}
96
97impl Default for OAuthConfig {
98    fn default() -> Self {
99        Self {
100            providers: vec![],
101            allow_implicit_account_linking: true,
102            success_redirect: None,
103            error_redirect: None,
104        }
105    }
106}
107
108impl Default for AuthConfig {
109    fn default() -> Self {
110        Self {
111            secret: String::new(),
112            session_ttl: Duration::days(30),
113            verification_ttl: Duration::hours(1),
114            reset_ttl: Duration::hours(1),
115            token_length: 32,
116            email: EmailConfig::default(),
117            cookie: CookieConfig::default(),
118            oauth: OAuthConfig::default(),
119        }
120    }
121}
122
123impl Default for EmailConfig {
124    fn default() -> Self {
125        Self {
126            send_verification_on_signup: true,
127            require_verification_to_login: false,
128            auto_sign_in_after_signup: true,
129            auto_sign_in_after_verification: false,
130        }
131    }
132}
133
134impl Default for CookieConfig {
135    fn default() -> Self {
136        Self {
137            name: "rs_auth_session".to_string(),
138            http_only: true,
139            secure: true,
140            same_site: SameSite::Lax,
141            path: "/".to_string(),
142            domain: None,
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn default_config_has_sane_values() {
153        let config = AuthConfig::default();
154
155        assert_eq!(
156            config.session_ttl,
157            Duration::days(30),
158            "session_ttl should be 30 days"
159        );
160        assert_eq!(config.token_length, 32, "token_length should be 32");
161        assert_eq!(
162            config.cookie.name, "rs_auth_session",
163            "cookie name should be 'rs_auth_session'"
164        );
165        assert_eq!(
166            config.verification_ttl,
167            Duration::hours(1),
168            "verification_ttl should be 1 hour"
169        );
170        assert_eq!(
171            config.reset_ttl,
172            Duration::hours(1),
173            "reset_ttl should be 1 hour"
174        );
175        assert!(config.cookie.http_only, "cookie should be http_only");
176        assert!(config.cookie.secure, "cookie should be secure");
177        assert_eq!(
178            config.cookie.same_site,
179            SameSite::Lax,
180            "cookie same_site should be Lax"
181        );
182        assert_eq!(config.cookie.path, "/", "cookie path should be '/'");
183        assert_eq!(config.cookie.domain, None, "cookie domain should be None");
184    }
185}