better_auth/core/
config.rs

1use std::sync::Arc;
2use chrono::Duration;
3use crate::adapters::DatabaseAdapter;
4use crate::error::AuthError;
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    /// Database adapter for persistence
16    pub database: Option<Arc<dyn DatabaseAdapter>>,
17    
18    /// Session configuration
19    pub session: SessionConfig,
20    
21    /// JWT configuration
22    pub jwt: JwtConfig,
23    
24    /// Password configuration
25    pub password: PasswordConfig,
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            database: None,
105            session: SessionConfig::default(),
106            jwt: JwtConfig::default(),
107            password: PasswordConfig::default(),
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("Secret key must be at least 32 characters"));
194        }
195        
196        if self.database.is_none() {
197            return Err(AuthError::config("Database adapter is required"));
198        }
199        
200        Ok(())
201    }
202}