Skip to main content

better_auth_core/
config.rs

1use crate::email::EmailProvider;
2use crate::error::AuthError;
3use chrono::Duration;
4use std::sync::Arc;
5
6/// Main configuration for BetterAuth
7#[derive(Clone)]
8pub struct AuthConfig {
9    /// Secret key for signing tokens and sessions
10    pub secret: String,
11
12    /// Base URL for the authentication service
13    pub base_url: String,
14
15    /// Session configuration
16    pub session: SessionConfig,
17
18    /// JWT configuration
19    pub jwt: JwtConfig,
20
21    /// Password configuration
22    pub password: PasswordConfig,
23
24    /// Email provider for sending emails (verification, password reset, etc.)
25    pub email_provider: Option<Arc<dyn EmailProvider>>,
26}
27
28/// Session-specific configuration
29#[derive(Debug, Clone)]
30pub struct SessionConfig {
31    /// Session expiration duration
32    pub expires_in: Duration,
33
34    /// Update session on activity
35    pub update_age: bool,
36
37    /// Cookie name for session token
38    pub cookie_name: String,
39
40    /// Cookie settings
41    pub cookie_secure: bool,
42    pub cookie_http_only: bool,
43    pub cookie_same_site: SameSite,
44}
45
46/// JWT configuration
47#[derive(Debug, Clone)]
48pub struct JwtConfig {
49    /// JWT expiration duration
50    pub expires_in: Duration,
51
52    /// JWT algorithm
53    pub algorithm: String,
54
55    /// Issuer claim
56    pub issuer: Option<String>,
57
58    /// Audience claim
59    pub audience: Option<String>,
60}
61
62/// Password hashing configuration
63#[derive(Debug, Clone)]
64pub struct PasswordConfig {
65    /// Minimum password length
66    pub min_length: usize,
67
68    /// Require uppercase letters
69    pub require_uppercase: bool,
70
71    /// Require lowercase letters
72    pub require_lowercase: bool,
73
74    /// Require numbers
75    pub require_numbers: bool,
76
77    /// Require special characters
78    pub require_special: bool,
79
80    /// Argon2 configuration
81    pub argon2_config: Argon2Config,
82}
83
84/// Argon2 hashing configuration
85#[derive(Debug, Clone)]
86pub struct Argon2Config {
87    pub memory_cost: u32,
88    pub time_cost: u32,
89    pub parallelism: u32,
90}
91
92#[derive(Debug, Clone)]
93pub enum SameSite {
94    Strict,
95    Lax,
96    None,
97}
98
99impl Default for AuthConfig {
100    fn default() -> Self {
101        Self {
102            secret: String::new(),
103            base_url: "http://localhost:3000".to_string(),
104            session: SessionConfig::default(),
105            jwt: JwtConfig::default(),
106            password: PasswordConfig::default(),
107            email_provider: None,
108        }
109    }
110}
111
112impl Default for SessionConfig {
113    fn default() -> Self {
114        Self {
115            expires_in: Duration::hours(24 * 7), // 7 days
116            update_age: true,
117            cookie_name: "better-auth.session-token".to_string(),
118            cookie_secure: true,
119            cookie_http_only: true,
120            cookie_same_site: SameSite::Lax,
121        }
122    }
123}
124
125impl Default for JwtConfig {
126    fn default() -> Self {
127        Self {
128            expires_in: Duration::hours(24), // 1 day
129            algorithm: "HS256".to_string(),
130            issuer: None,
131            audience: None,
132        }
133    }
134}
135
136impl Default for PasswordConfig {
137    fn default() -> Self {
138        Self {
139            min_length: 8,
140            require_uppercase: false,
141            require_lowercase: false,
142            require_numbers: false,
143            require_special: false,
144            argon2_config: Argon2Config::default(),
145        }
146    }
147}
148
149impl Default for Argon2Config {
150    fn default() -> Self {
151        Self {
152            memory_cost: 4096, // 4MB
153            time_cost: 3,      // 3 iterations
154            parallelism: 1,    // 1 thread
155        }
156    }
157}
158
159impl AuthConfig {
160    pub fn new(secret: impl Into<String>) -> Self {
161        Self {
162            secret: secret.into(),
163            ..Default::default()
164        }
165    }
166
167    pub fn base_url(mut self, url: impl Into<String>) -> Self {
168        self.base_url = url.into();
169        self
170    }
171
172    pub fn session_expires_in(mut self, duration: Duration) -> Self {
173        self.session.expires_in = duration;
174        self
175    }
176
177    pub fn jwt_expires_in(mut self, duration: Duration) -> Self {
178        self.jwt.expires_in = duration;
179        self
180    }
181
182    pub fn password_min_length(mut self, length: usize) -> Self {
183        self.password.min_length = length;
184        self
185    }
186
187    pub fn validate(&self) -> Result<(), AuthError> {
188        if self.secret.is_empty() {
189            return Err(AuthError::config("Secret key cannot be empty"));
190        }
191
192        if self.secret.len() < 32 {
193            return Err(AuthError::config(
194                "Secret key must be at least 32 characters",
195            ));
196        }
197
198        Ok(())
199    }
200}