Skip to main content

better_auth_core/
config.rs

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