Skip to main content

openauth_core/options/
root.rs

1use std::fmt;
2use std::sync::Arc;
3
4#[cfg(feature = "oauth")]
5use openauth_oauth::oauth2::SocialOAuthProvider;
6
7use super::storage::SecondaryStorage;
8use crate::crypto::SecretEntry;
9use crate::plugin::AuthPlugin;
10
11use super::account::AccountOptions;
12use super::advanced::AdvancedOptions;
13use super::email_password::EmailPasswordOptions;
14use super::email_verification::EmailVerificationOptions;
15use super::origins::TrustedOriginOptions;
16use super::password::PasswordOptions;
17use super::rate_limit::RateLimitOptions;
18use super::session::SessionOptions;
19use super::user::UserOptions;
20
21/// Telemetry collection settings (parity with Better Auth `telemetry` init option).
22#[derive(Debug, Clone, PartialEq, Eq, Default)]
23pub struct TelemetryOptions {
24    /// When `None`, option-side telemetry is off unless overridden by environment.
25    pub enabled: Option<bool>,
26    pub debug: bool,
27}
28
29impl TelemetryOptions {
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    #[must_use]
35    pub fn enabled(mut self, enabled: bool) -> Self {
36        self.enabled = Some(enabled);
37        self
38    }
39
40    #[must_use]
41    pub fn debug(mut self, debug: bool) -> Self {
42        self.debug = debug;
43        self
44    }
45}
46
47/// Experimental feature flags.
48#[derive(Debug, Clone, PartialEq, Eq, Default)]
49pub struct ExperimentalOptions {
50    pub joins: bool,
51}
52
53impl ExperimentalOptions {
54    pub fn new() -> Self {
55        Self::default()
56    }
57
58    #[must_use]
59    pub fn joins(mut self, enabled: bool) -> Self {
60        self.joins = enabled;
61        self
62    }
63}
64
65/// Top-level OpenAuth configuration.
66#[derive(Clone, Default)]
67pub struct OpenAuthOptions {
68    pub base_url: Option<String>,
69    pub base_path: Option<String>,
70    pub secret: Option<String>,
71    pub secrets: Vec<SecretEntry>,
72    pub trusted_origins: TrustedOriginOptions,
73    pub disabled_paths: Vec<String>,
74    pub session: SessionOptions,
75    pub user: UserOptions,
76    pub email_password: EmailPasswordOptions,
77    pub email_verification: EmailVerificationOptions,
78    pub password: PasswordOptions,
79    pub account: AccountOptions,
80    pub advanced: AdvancedOptions,
81    pub rate_limit: RateLimitOptions,
82    pub secondary_storage: Option<Arc<dyn SecondaryStorage>>,
83    pub plugins: Vec<AuthPlugin>,
84    #[cfg(feature = "oauth")]
85    pub social_providers: Vec<Arc<dyn SocialOAuthProvider>>,
86    pub production: bool,
87    pub telemetry: TelemetryOptions,
88    pub experimental: ExperimentalOptions,
89}
90
91impl OpenAuthOptions {
92    pub fn new() -> Self {
93        Self::default()
94    }
95
96    pub fn builder() -> Self {
97        Self::new()
98    }
99
100    #[must_use]
101    pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
102        self.base_url = Some(base_url.into());
103        self
104    }
105
106    #[must_use]
107    pub fn base_path(mut self, base_path: impl Into<String>) -> Self {
108        self.base_path = Some(base_path.into());
109        self
110    }
111
112    #[must_use]
113    pub fn secret(mut self, secret: impl Into<String>) -> Self {
114        self.secret = Some(secret.into());
115        self
116    }
117
118    #[must_use]
119    pub fn secrets(mut self, secrets: Vec<SecretEntry>) -> Self {
120        self.secrets = secrets;
121        self
122    }
123
124    #[must_use]
125    pub fn trusted_origins(mut self, trusted_origins: TrustedOriginOptions) -> Self {
126        self.trusted_origins = trusted_origins;
127        self
128    }
129
130    #[must_use]
131    pub fn disabled_path(mut self, path: impl Into<String>) -> Self {
132        self.disabled_paths.push(path.into());
133        self
134    }
135
136    #[must_use]
137    pub fn disabled_paths<I, S>(mut self, paths: I) -> Self
138    where
139        I: IntoIterator<Item = S>,
140        S: Into<String>,
141    {
142        self.disabled_paths = paths.into_iter().map(Into::into).collect();
143        self
144    }
145
146    #[must_use]
147    pub fn session(mut self, session: SessionOptions) -> Self {
148        self.session = session;
149        self
150    }
151
152    #[must_use]
153    pub fn user(mut self, user: UserOptions) -> Self {
154        self.user = user;
155        self
156    }
157
158    #[must_use]
159    pub fn email_password(mut self, email_password: EmailPasswordOptions) -> Self {
160        self.email_password = email_password;
161        self
162    }
163
164    #[must_use]
165    pub fn email_verification(mut self, email_verification: EmailVerificationOptions) -> Self {
166        self.email_verification = email_verification;
167        self
168    }
169
170    #[must_use]
171    pub fn password(mut self, password: PasswordOptions) -> Self {
172        self.password = password;
173        self
174    }
175
176    #[must_use]
177    pub fn account(mut self, account: AccountOptions) -> Self {
178        self.account = account;
179        self
180    }
181
182    #[must_use]
183    pub fn advanced(mut self, advanced: AdvancedOptions) -> Self {
184        self.advanced = advanced;
185        self
186    }
187
188    #[must_use]
189    pub fn rate_limit(mut self, rate_limit: RateLimitOptions) -> Self {
190        self.rate_limit = rate_limit;
191        self
192    }
193
194    #[must_use]
195    pub fn secondary_storage(mut self, storage: Arc<dyn SecondaryStorage>) -> Self {
196        self.secondary_storage = Some(storage);
197        self
198    }
199
200    #[must_use]
201    pub fn plugin(mut self, plugin: AuthPlugin) -> Self {
202        self.plugins.push(plugin);
203        self
204    }
205
206    #[must_use]
207    pub fn plugins(mut self, plugins: Vec<AuthPlugin>) -> Self {
208        self.plugins = plugins;
209        self
210    }
211
212    #[cfg(feature = "oauth")]
213    #[must_use]
214    pub fn social_provider<P>(mut self, provider: P) -> Self
215    where
216        P: SocialOAuthProvider,
217    {
218        self.social_providers.push(Arc::new(provider));
219        self
220    }
221
222    #[cfg(feature = "oauth")]
223    #[must_use]
224    pub fn social_provider_arc(mut self, provider: Arc<dyn SocialOAuthProvider>) -> Self {
225        self.social_providers.push(provider);
226        self
227    }
228
229    #[must_use]
230    pub fn production(mut self, production: bool) -> Self {
231        self.production = production;
232        self
233    }
234
235    #[must_use]
236    pub fn telemetry(mut self, telemetry: TelemetryOptions) -> Self {
237        self.telemetry = telemetry;
238        self
239    }
240
241    #[must_use]
242    pub fn experimental(mut self, experimental: ExperimentalOptions) -> Self {
243        self.experimental = experimental;
244        self
245    }
246}
247
248impl fmt::Debug for OpenAuthOptions {
249    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
250        formatter
251            .debug_struct("OpenAuthOptions")
252            .field("base_url", &self.base_url)
253            .field("base_path", &self.base_path)
254            .field("secret", &self.secret.as_ref().map(|_| "<redacted>"))
255            .field(
256                "secrets",
257                &format_args!("{} secret(s) redacted", self.secrets.len()),
258            )
259            .field("trusted_origins", &self.trusted_origins)
260            .field("disabled_paths", &self.disabled_paths)
261            .field("session", &self.session)
262            .field("user", &self.user)
263            .field("email_password", &self.email_password)
264            .field("email_verification", &self.email_verification)
265            .field("password", &self.password)
266            .field("account", &self.account)
267            .field("advanced", &self.advanced)
268            .field("rate_limit", &self.rate_limit)
269            .field(
270                "secondary_storage",
271                &self
272                    .secondary_storage
273                    .as_ref()
274                    .map(|_| "<secondary-storage>"),
275            )
276            .field("plugins", &self.plugins)
277            .field("social_providers", &debug_social_providers(self))
278            .field("production", &self.production)
279            .field("telemetry", &self.telemetry)
280            .field("experimental", &self.experimental)
281            .finish()
282    }
283}
284
285#[cfg(feature = "oauth")]
286fn debug_social_providers(options: &OpenAuthOptions) -> Vec<&str> {
287    options
288        .social_providers
289        .iter()
290        .map(|provider| provider.id())
291        .collect()
292}
293
294#[cfg(not(feature = "oauth"))]
295fn debug_social_providers(_options: &OpenAuthOptions) -> Vec<&'static str> {
296    Vec::new()
297}