Skip to main content

auth_framework/
builders.rs

1//! Builder patterns and ergonomic helpers for the Auth Framework
2//!
3//! This module provides fluent builder APIs and helper functions to make
4//! common authentication setup tasks easier and more discoverable.
5//!
6//! # Quick Start Builders
7//!
8//! For the most common setups, use the quick start builders:
9//!
10//! ```rust,no_run
11//! # #[tokio::main]
12//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
13//! use auth_framework::prelude::*;
14//!
15//! // Simple JWT auth with environment variables
16//! let auth = AuthFramework::quick_start()
17//!     .jwt_auth_from_env()
18//!     .build().await?;
19//!
20//! // Web app with database
21//! let auth = AuthFramework::quick_start()
22//!     .jwt_auth("your-secret-key")
23//!     .with_postgres("postgresql://...")
24//!     .with_axum()
25//!     .build().await?;
26//! # Ok(())
27//! # }
28//! ```
29//!
30//! # Preset Configurations
31//!
32//! Use presets for common security and performance configurations:
33//!
34//! ```rust,no_run
35//! # #[tokio::main]
36//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
37//! use auth_framework::prelude::*;
38//!
39//! let auth = AuthFramework::builder()
40//!     .security_preset(SecurityPreset::HighSecurity)
41//!     .performance_preset(PerformancePreset::LowLatency)
42//!     .build().await?;
43//! # Ok(())
44//! # }
45//! ```
46//!
47//! # Use Case Templates
48//!
49//! Get started quickly with templates for common use cases:
50//!
51//! ```rust,no_run
52//! # #[tokio::main]
53//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
54//! use auth_framework::prelude::*;
55//!
56//! // Configure for web application
57//! let auth = AuthFramework::for_use_case(UseCasePreset::WebApp)
58//!     .customize(|config| {
59//!         config.token_lifetime = hours(24);
60//!         config
61//!     })
62//!     .build().await?;
63//! # Ok(())
64//! # }
65//! ```
66
67use crate::{
68    AuthConfig, AuthError, AuthFramework,
69    config::{RateLimitConfig, SecurityConfig, StorageConfig},
70    prelude::{PerformancePreset, UseCasePreset, days, hours, minutes},
71    security::SecurityPreset,
72};
73use std::time::Duration;
74#[cfg(not(feature = "redis-storage"))]
75use tracing::warn;
76
77/// Main builder for constructing an [`AuthFramework`] instance.
78///
79/// Start with [`AuthFramework::builder()`] and chain sub-builders for
80/// JWT, storage, security, rate limiting, and audit configuration.
81///
82/// # Example
83///
84/// ```rust,no_run
85/// # #[tokio::main]
86/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
87/// use auth_framework::prelude::*;
88///
89/// let auth = AuthFramework::builder()
90///     .with_jwt().secret("my-secret-key-that-is-long-enough!!").issuer("myapp").done()
91///     .with_storage().memory().done()
92///     .security_preset(SecurityPreset::Balanced)
93///     .build().await?;
94/// # Ok(())
95/// # }
96/// ```
97pub struct AuthBuilder {
98    config: AuthConfig,
99    security_preset: Option<SecurityPreset>,
100    performance_preset: Option<PerformancePreset>,
101    use_case_preset: Option<UseCasePreset>,
102    storage_pool_size: Option<u32>,
103    /// Optional custom storage instance supplied by caller (`Arc<dyn AuthStorage>`)
104    custom_storage: Option<std::sync::Arc<dyn crate::storage::AuthStorage>>,
105}
106
107/// Quick start builder for common authentication setups.
108///
109/// Provides the fastest path to a working [`AuthFramework`] by combining
110/// authentication method, storage, and framework integrations in a single
111/// fluent chain.  Start via [`AuthFramework::quick_start()`].
112///
113/// # Example
114///
115/// ```rust,no_run
116/// # #[tokio::main]
117/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
118/// use auth_framework::prelude::*;
119///
120/// let auth = AuthFramework::quick_start()
121///     .jwt_auth("my-secret-key-that-is-long-enough!!")
122///     .build().await?;
123/// # Ok(())
124/// # }
125/// ```
126#[derive(Debug)]
127pub struct QuickStartBuilder {
128    auth_method: Option<QuickStartAuth>,
129    storage: Option<QuickStartStorage>,
130    framework: Option<QuickStartFramework>,
131    security_level: SecurityPreset,
132}
133
134/// Authentication method selection for [`QuickStartBuilder`].
135#[derive(Debug)]
136pub enum QuickStartAuth {
137    Jwt {
138        secret: String,
139    },
140    JwtFromEnv,
141    OAuth2 {
142        client_id: String,
143        client_secret: String,
144    },
145    Combined {
146        jwt_secret: String,
147        oauth_client_id: String,
148        oauth_client_secret: String,
149    },
150}
151
152/// Storage backend selection for [`QuickStartBuilder`].
153#[derive(Debug)]
154pub enum QuickStartStorage {
155    Memory,
156    Postgres(String),
157    PostgresFromEnv,
158    Redis(String),
159    RedisFromEnv,
160}
161
162/// Web framework integration selection for [`QuickStartBuilder`].
163#[derive(Debug)]
164pub enum QuickStartFramework {
165    Axum,
166    ActixWeb,
167    Warp,
168}
169
170impl AuthFramework {
171    /// Create a new builder for the authentication framework
172    pub fn builder() -> AuthBuilder {
173        AuthBuilder::new()
174    }
175
176    /// Quick start builder for common setups
177    pub fn quick_start() -> QuickStartBuilder {
178        QuickStartBuilder::new()
179    }
180
181    /// Create a builder for a specific use case
182    pub fn for_use_case(use_case: UseCasePreset) -> AuthBuilder {
183        AuthBuilder::new().use_case_preset(use_case)
184    }
185
186    /// Create an authentication framework with preset configuration
187    pub fn preset(preset: SecurityPreset) -> AuthBuilder {
188        AuthBuilder::new().security_preset(preset)
189    }
190}
191
192impl AuthBuilder {
193    /// Create a new builder with default configuration.
194    ///
195    /// # Example
196    ///
197    /// ```rust
198    /// use auth_framework::builders::AuthBuilder;
199    ///
200    /// let builder = AuthBuilder::new();
201    /// ```
202    pub fn new() -> Self {
203        Self {
204            config: AuthConfig::default(),
205            security_preset: None,
206            performance_preset: None,
207            use_case_preset: None,
208            storage_pool_size: None,
209            custom_storage: None,
210        }
211    }
212
213    /// Apply a security preset.
214    ///
215    /// # Example
216    ///
217    /// ```rust,no_run
218    /// use auth_framework::prelude::*;
219    ///
220    /// let builder = AuthFramework::builder()
221    ///     .security_preset(SecurityPreset::HighSecurity);
222    /// ```
223    pub fn security_preset(mut self, preset: SecurityPreset) -> Self {
224        self.security_preset = Some(preset);
225        self
226    }
227
228    /// Apply a performance preset.
229    ///
230    /// # Example
231    ///
232    /// ```rust,no_run
233    /// use auth_framework::prelude::*;
234    ///
235    /// let builder = AuthFramework::builder()
236    ///     .performance_preset(PerformancePreset::LowLatency);
237    /// ```
238    pub fn performance_preset(mut self, preset: PerformancePreset) -> Self {
239        self.performance_preset = Some(preset);
240        self
241    }
242
243    /// Apply a use case preset.
244    ///
245    /// # Example
246    ///
247    /// ```rust,no_run
248    /// use auth_framework::prelude::*;
249    ///
250    /// let builder = AuthFramework::builder()
251    ///     .use_case_preset(UseCasePreset::WebApp);
252    /// ```
253    pub fn use_case_preset(mut self, preset: UseCasePreset) -> Self {
254        self.use_case_preset = Some(preset);
255        self
256    }
257
258    /// Configure JWT authentication.
259    ///
260    /// Returns a [`JwtBuilder`] sub-builder. Call `.done()` to return.
261    ///
262    /// # Example
263    ///
264    /// ```rust,no_run
265    /// use auth_framework::prelude::*;
266    ///
267    /// let builder = AuthFramework::builder()
268    ///     .with_jwt().secret("my-long-secret-key-32-chars-min!!").done();
269    /// ```
270    pub fn with_jwt(self) -> JwtBuilder {
271        JwtBuilder::new(self)
272    }
273
274    /// Configure OAuth2 authentication.
275    ///
276    /// Returns an [`OAuth2Builder`] sub-builder. Call `.done()` to return.
277    ///
278    /// # Example
279    ///
280    /// ```rust,no_run
281    /// use auth_framework::prelude::*;
282    ///
283    /// let builder = AuthFramework::builder()
284    ///     .with_oauth2().client_id("id").client_secret("secret").done();
285    /// ```
286    pub fn with_oauth2(self) -> OAuth2Builder {
287        OAuth2Builder::new(self)
288    }
289
290    /// Configure storage backend.
291    ///
292    /// Returns a [`StorageBuilder`] sub-builder. Call `.done()` to return.
293    ///
294    /// # Example
295    ///
296    /// ```rust,no_run
297    /// use auth_framework::prelude::*;
298    ///
299    /// let builder = AuthFramework::builder()
300    ///     .with_storage().memory().done();
301    /// ```
302    pub fn with_storage(self) -> StorageBuilder {
303        StorageBuilder::new(self)
304    }
305
306    /// Configure rate limiting.
307    ///
308    /// Returns a [`RateLimitBuilder`] sub-builder. Call `.done()` to return.
309    ///
310    /// # Example
311    ///
312    /// ```rust,no_run
313    /// use auth_framework::prelude::*;
314    /// use std::time::Duration;
315    ///
316    /// let builder = AuthFramework::builder()
317    ///     .with_rate_limiting().per_ip((200, Duration::from_secs(60))).done();
318    /// ```
319    pub fn with_rate_limiting(self) -> RateLimitBuilder {
320        RateLimitBuilder::new(self)
321    }
322
323    /// Configure security settings.
324    ///
325    /// Returns a [`SecurityBuilder`] sub-builder. Call `.done()` to return.
326    ///
327    /// # Example
328    ///
329    /// ```rust,no_run
330    /// use auth_framework::prelude::*;
331    ///
332    /// let builder = AuthFramework::builder()
333    ///     .with_security().min_password_length(12).secure_cookies(true).done();
334    /// ```
335    pub fn with_security(self) -> SecurityBuilder {
336        SecurityBuilder::new(self)
337    }
338
339    /// Configure audit logging.
340    ///
341    /// Returns an [`AuditBuilder`] sub-builder. Call `.done()` to return.
342    ///
343    /// # Example
344    ///
345    /// ```rust,no_run
346    /// use auth_framework::prelude::*;
347    ///
348    /// let builder = AuthFramework::builder()
349    ///     .with_audit().enabled(true).log_success(true).done();
350    /// ```
351    pub fn with_audit(self) -> AuditBuilder {
352        AuditBuilder::new(self)
353    }
354
355    /// Customize configuration with a closure.
356    ///
357    /// # Example
358    ///
359    /// ```rust,no_run
360    /// use auth_framework::prelude::*;
361    /// use std::time::Duration;
362    ///
363    /// let builder = AuthFramework::builder()
364    ///     .customize(|config| {
365    ///         config.token_lifetime = Duration::from_secs(7200);
366    ///         config
367    ///     });
368    /// ```
369    pub fn customize<F>(mut self, f: F) -> Self
370    where
371        F: FnOnce(&mut AuthConfig) -> &mut AuthConfig,
372    {
373        f(&mut self.config);
374        self
375    }
376
377    /// Build the authentication framework.
378    ///
379    /// Applies presets, validates configuration, initializes storage,
380    /// and returns a ready-to-use [`AuthFramework`] instance.
381    ///
382    /// # Example
383    ///
384    /// ```rust,no_run
385    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
386    /// use auth_framework::prelude::*;
387    ///
388    /// let auth = AuthFramework::builder()
389    ///     .with_jwt().secret("my-long-secret-key-32-chars-min!!").done()
390    ///     .with_storage().memory().done()
391    ///     .build().await?;
392    /// # Ok(()) }
393    /// ```
394    pub async fn build(mut self) -> Result<AuthFramework, AuthError> {
395        // Apply presets before building
396        if let Some(preset) = self.security_preset.take() {
397            self.config.security = self.apply_security_preset(preset);
398        }
399
400        if let Some(preset) = self.performance_preset.take() {
401            self.apply_performance_preset(preset);
402        }
403
404        if let Some(preset) = self.use_case_preset.take() {
405            self.apply_use_case_preset(preset);
406        }
407
408        // Validate configuration
409        self.config.validate()?;
410
411        // Create and initialize framework
412        // If a custom storage was provided via the builder, we'll construct a framework
413        // and replace its storage before initialization so managers use the custom storage.
414        let config = self.config.clone();
415        let mut framework = AuthFramework::new(self.config);
416        if let Some(storage) = self.custom_storage.take() {
417            framework.replace_storage(storage);
418        } else if let Some(pool_size) = self.storage_pool_size {
419            let storage =
420                crate::storage::factory::build_storage_backend(&config.storage, Some(pool_size))
421                    .await?;
422            framework.replace_storage(storage);
423        }
424        framework.initialize().await?;
425
426        Ok(framework)
427    }
428
429    fn apply_security_preset(&self, preset: SecurityPreset) -> SecurityConfig {
430        match preset {
431            SecurityPreset::Development => SecurityConfig::development(),
432            SecurityPreset::Balanced => SecurityConfig::default(),
433            SecurityPreset::HighSecurity | SecurityPreset::Paranoid => SecurityConfig::secure(),
434        }
435    }
436
437    fn apply_performance_preset(&mut self, preset: PerformancePreset) {
438        match preset {
439            PerformancePreset::HighThroughput => {
440                // Optimize for throughput
441                self.config.rate_limiting.max_requests = 1000;
442                self.config.rate_limiting.window = Duration::from_secs(60);
443            }
444            PerformancePreset::LowLatency => {
445                // Optimize for latency
446                self.config.token_lifetime = hours(1);
447                self.config.rate_limiting.max_requests = 100;
448                self.config.rate_limiting.window = Duration::from_secs(60);
449            }
450            PerformancePreset::LowMemory => {
451                // Optimize for memory usage
452                self.config.token_lifetime = minutes(15);
453                self.config.refresh_token_lifetime = hours(2);
454            }
455            PerformancePreset::Balanced => {
456                // Keep defaults
457            }
458        }
459    }
460
461    fn apply_use_case_preset(&mut self, preset: UseCasePreset) {
462        match preset {
463            UseCasePreset::WebApp => {
464                self.config.token_lifetime = hours(24);
465                self.config.refresh_token_lifetime = days(7);
466                self.config.security.secure_cookies = true;
467                self.config.security.csrf_protection = true;
468            }
469            UseCasePreset::ApiService => {
470                self.config.token_lifetime = hours(1);
471                self.config.refresh_token_lifetime = hours(24);
472                self.config.rate_limiting.enabled = true;
473                self.config.rate_limiting.max_requests = 1000;
474            }
475            UseCasePreset::Microservices => {
476                self.config.token_lifetime = minutes(15);
477                self.config.refresh_token_lifetime = hours(1);
478                self.config.audit.enabled = true;
479            }
480            UseCasePreset::MobileBackend => {
481                self.config.token_lifetime = hours(1);
482                self.config.refresh_token_lifetime = days(30);
483                self.config.security.secure_cookies = false; // Mobile doesn't use cookies
484            }
485            UseCasePreset::Enterprise => {
486                self.config.enable_multi_factor = true;
487                self.config.security = SecurityConfig::secure();
488                self.config.audit.enabled = true;
489                self.config.audit.log_success = true;
490                self.config.audit.log_failures = true;
491            }
492        }
493    }
494}
495
496impl QuickStartBuilder {
497    fn new() -> Self {
498        Self {
499            auth_method: None,
500            storage: None,
501            framework: None,
502            security_level: SecurityPreset::Balanced,
503        }
504    }
505
506    /// Configure JWT authentication with a secret key.
507    ///
508    /// # Example
509    ///
510    /// ```rust,no_run
511    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
512    /// use auth_framework::prelude::*;
513    ///
514    /// let auth = AuthFramework::quick_start()
515    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
516    ///     .build().await?;
517    /// # Ok(()) }
518    /// ```
519    pub fn jwt_auth(mut self, secret: impl Into<String>) -> Self {
520        self.auth_method = Some(QuickStartAuth::Jwt {
521            secret: secret.into(),
522        });
523        self
524    }
525
526    /// Configure JWT authentication from `JWT_SECRET` environment variable.
527    ///
528    /// # Example
529    ///
530    /// ```rust,no_run
531    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
532    /// use auth_framework::prelude::*;
533    ///
534    /// // Reads JWT_SECRET from the environment
535    /// let auth = AuthFramework::quick_start()
536    ///     .jwt_auth_from_env()
537    ///     .build().await?;
538    /// # Ok(()) }
539    /// ```
540    pub fn jwt_auth_from_env(mut self) -> Self {
541        self.auth_method = Some(QuickStartAuth::JwtFromEnv);
542        self
543    }
544
545    /// Configure OAuth2 authentication.
546    ///
547    /// # Example
548    ///
549    /// ```rust,no_run
550    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
551    /// use auth_framework::prelude::*;
552    ///
553    /// let auth = AuthFramework::quick_start()
554    ///     .oauth2_auth("client-id", "client-secret")
555    ///     .build().await?;
556    /// # Ok(()) }
557    /// ```
558    pub fn oauth2_auth(
559        mut self,
560        client_id: impl Into<String>,
561        client_secret: impl Into<String>,
562    ) -> Self {
563        self.auth_method = Some(QuickStartAuth::OAuth2 {
564            client_id: client_id.into(),
565            client_secret: client_secret.into(),
566        });
567        self
568    }
569
570    /// Configure both JWT and OAuth2 authentication.
571    ///
572    /// # Example
573    ///
574    /// ```rust,no_run
575    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
576    /// use auth_framework::prelude::*;
577    ///
578    /// let auth = AuthFramework::quick_start()
579    ///     .combined_auth("jwt-secret-long-enough-32chars!!", "client-id", "secret")
580    ///     .build().await?;
581    /// # Ok(()) }
582    /// ```
583    pub fn combined_auth(
584        mut self,
585        jwt_secret: impl Into<String>,
586        oauth_client_id: impl Into<String>,
587        oauth_client_secret: impl Into<String>,
588    ) -> Self {
589        self.auth_method = Some(QuickStartAuth::Combined {
590            jwt_secret: jwt_secret.into(),
591            oauth_client_id: oauth_client_id.into(),
592            oauth_client_secret: oauth_client_secret.into(),
593        });
594        self
595    }
596
597    /// Use PostgreSQL storage with connection string.
598    ///
599    /// # Example
600    ///
601    /// ```rust,no_run
602    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
603    /// use auth_framework::prelude::*;
604    ///
605    /// let auth = AuthFramework::quick_start()
606    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
607    ///     .with_postgres("postgresql://user:pass@localhost/auth")
608    ///     .build().await?;
609    /// # Ok(()) }
610    /// ```
611    pub fn with_postgres(mut self, connection_string: impl Into<String>) -> Self {
612        self.storage = Some(QuickStartStorage::Postgres(connection_string.into()));
613        self
614    }
615
616    /// Use PostgreSQL storage from `DATABASE_URL` environment variable.
617    ///
618    /// # Example
619    ///
620    /// ```rust,no_run
621    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
622    /// use auth_framework::prelude::*;
623    ///
624    /// let auth = AuthFramework::quick_start()
625    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
626    ///     .with_postgres_from_env()
627    ///     .build().await?;
628    /// # Ok(()) }
629    /// ```
630    pub fn with_postgres_from_env(mut self) -> Self {
631        self.storage = Some(QuickStartStorage::PostgresFromEnv);
632        self
633    }
634
635    /// Use Redis storage with connection string.
636    ///
637    /// # Example
638    ///
639    /// ```rust,no_run
640    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
641    /// use auth_framework::prelude::*;
642    ///
643    /// let auth = AuthFramework::quick_start()
644    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
645    ///     .with_redis("redis://localhost:6379")
646    ///     .build().await?;
647    /// # Ok(()) }
648    /// ```
649    pub fn with_redis(mut self, connection_string: impl Into<String>) -> Self {
650        self.storage = Some(QuickStartStorage::Redis(connection_string.into()));
651        self
652    }
653
654    /// Use Redis storage from `REDIS_URL` environment variable.
655    ///
656    /// # Example
657    ///
658    /// ```rust,no_run
659    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
660    /// use auth_framework::prelude::*;
661    ///
662    /// let auth = AuthFramework::quick_start()
663    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
664    ///     .with_redis_from_env()
665    ///     .build().await?;
666    /// # Ok(()) }
667    /// ```
668    pub fn with_redis_from_env(mut self) -> Self {
669        self.storage = Some(QuickStartStorage::RedisFromEnv);
670        self
671    }
672
673    /// Use in-memory storage (development only).
674    ///
675    /// # Example
676    ///
677    /// ```rust,no_run
678    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
679    /// use auth_framework::prelude::*;
680    ///
681    /// let auth = AuthFramework::quick_start()
682    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
683    ///     .with_memory_storage()
684    ///     .build().await?;
685    /// # Ok(()) }
686    /// ```
687    pub fn with_memory_storage(mut self) -> Self {
688        self.storage = Some(QuickStartStorage::Memory);
689        self
690    }
691
692    /// Configure for Axum web framework.
693    ///
694    /// # Example
695    ///
696    /// ```rust,no_run
697    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
698    /// use auth_framework::prelude::*;
699    ///
700    /// let auth = AuthFramework::quick_start()
701    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
702    ///     .with_axum()
703    ///     .build().await?;
704    /// # Ok(()) }
705    /// ```
706    pub fn with_axum(mut self) -> Self {
707        self.framework = Some(QuickStartFramework::Axum);
708        self
709    }
710
711    /// Configure for Actix Web framework.
712    ///
713    /// # Example
714    ///
715    /// ```rust,no_run
716    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
717    /// use auth_framework::prelude::*;
718    ///
719    /// let auth = AuthFramework::quick_start()
720    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
721    ///     .with_actix()
722    ///     .build().await?;
723    /// # Ok(()) }
724    /// ```
725    pub fn with_actix(mut self) -> Self {
726        self.framework = Some(QuickStartFramework::ActixWeb);
727        self
728    }
729
730    /// Configure for Warp web framework.
731    ///
732    /// # Example
733    ///
734    /// ```rust,no_run
735    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
736    /// use auth_framework::prelude::*;
737    ///
738    /// let auth = AuthFramework::quick_start()
739    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
740    ///     .with_warp()
741    ///     .build().await?;
742    /// # Ok(()) }
743    /// ```
744    pub fn with_warp(mut self) -> Self {
745        self.framework = Some(QuickStartFramework::Warp);
746        self
747    }
748
749    /// Set security level.
750    ///
751    /// # Example
752    ///
753    /// ```rust,no_run
754    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
755    /// use auth_framework::prelude::*;
756    ///
757    /// let auth = AuthFramework::quick_start()
758    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
759    ///     .security_level(SecurityPreset::HighSecurity)
760    ///     .build().await?;
761    /// # Ok(()) }
762    /// ```
763    pub fn security_level(mut self, level: SecurityPreset) -> Self {
764        self.security_level = level;
765        self
766    }
767
768    /// Build the authentication framework.
769    ///
770    /// Applies the configured auth method, storage, and security level,
771    /// then delegates to [`AuthBuilder::build`].
772    ///
773    /// # Example
774    ///
775    /// ```rust,no_run
776    /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
777    /// use auth_framework::prelude::*;
778    ///
779    /// let auth = AuthFramework::quick_start()
780    ///     .jwt_auth("my-long-secret-key-32-chars-min!!")
781    ///     .build().await?;
782    /// # Ok(()) }
783    /// ```
784    pub async fn build(self) -> Result<AuthFramework, AuthError> {
785        let mut builder = AuthBuilder::new().security_preset(self.security_level);
786
787        // Configure authentication method
788        match self.auth_method {
789            Some(QuickStartAuth::Jwt { secret }) => {
790                builder = builder.with_jwt().secret(secret).done();
791            }
792            Some(QuickStartAuth::JwtFromEnv) => {
793                let secret = std::env::var("JWT_SECRET").map_err(|_| {
794                    AuthError::config("JWT_SECRET environment variable is required")
795                })?;
796                builder = builder.with_jwt().secret(secret).done();
797            }
798            Some(QuickStartAuth::OAuth2 {
799                client_id,
800                client_secret,
801            }) => {
802                builder = builder
803                    .with_oauth2()
804                    .client_id(client_id)
805                    .client_secret(client_secret)
806                    .done();
807            }
808            Some(QuickStartAuth::Combined {
809                jwt_secret,
810                oauth_client_id,
811                oauth_client_secret,
812            }) => {
813                builder = builder
814                    .with_jwt()
815                    .secret(jwt_secret)
816                    .done()
817                    .with_oauth2()
818                    .client_id(oauth_client_id)
819                    .client_secret(oauth_client_secret)
820                    .done();
821            }
822            None => {
823                return Err(AuthError::config("Authentication method is required"));
824            }
825        }
826
827        // Configure storage
828        match self.storage {
829            Some(QuickStartStorage::Memory) => {
830                builder = builder.with_storage().memory().done();
831            }
832            Some(QuickStartStorage::Postgres(_conn_str)) => {
833                #[cfg(feature = "postgres-storage")]
834                {
835                    builder = builder.with_storage().postgres(_conn_str).done();
836                }
837                #[cfg(not(feature = "postgres-storage"))]
838                {
839                    warn!(
840                        "PostgreSQL storage requested but the `postgres-storage` feature is not enabled; \
841                         falling back to in-memory storage"
842                    );
843                    builder = builder.with_storage().memory().done();
844                }
845            }
846            Some(QuickStartStorage::PostgresFromEnv) => {
847                #[cfg(feature = "postgres-storage")]
848                {
849                    let conn_str = std::env::var("DATABASE_URL").map_err(|_| {
850                        AuthError::config("DATABASE_URL environment variable is required")
851                    })?;
852                    builder = builder.with_storage().postgres(conn_str).done();
853                }
854                #[cfg(not(feature = "postgres-storage"))]
855                {
856                    warn!(
857                        "PostgreSQL storage requested but the `postgres-storage` feature is not enabled; \
858                         falling back to in-memory storage"
859                    );
860                    builder = builder.with_storage().memory().done();
861                }
862            }
863            Some(QuickStartStorage::Redis(_conn_str)) => {
864                #[cfg(feature = "redis-storage")]
865                {
866                    builder = builder.with_storage().redis(_conn_str).done();
867                }
868                #[cfg(not(feature = "redis-storage"))]
869                {
870                    warn!(
871                        "Redis storage requested but the `redis-storage` feature is not enabled; \
872                         falling back to in-memory storage"
873                    );
874                    builder = builder.with_storage().memory().done();
875                }
876            }
877            Some(QuickStartStorage::RedisFromEnv) => {
878                #[cfg(feature = "redis-storage")]
879                {
880                    builder = builder.with_storage().redis_from_env().done();
881                }
882                #[cfg(not(feature = "redis-storage"))]
883                {
884                    warn!(
885                        "Redis storage requested but the `redis-storage` feature is not enabled; \
886                         falling back to in-memory storage"
887                    );
888                    builder = builder.with_storage().memory().done();
889                }
890            }
891            None => {
892                // Default to memory storage for quick start
893                builder = builder.with_storage().memory().done();
894            }
895        }
896
897        builder.build().await
898    }
899}
900
901/// Sub-builder for JWT settings.
902///
903/// Entered via [`AuthBuilder::with_jwt()`]; call [`done()`](JwtBuilder::done)
904/// to return to the parent builder.
905pub struct JwtBuilder {
906    parent: AuthBuilder,
907    secret: Option<String>,
908    issuer: Option<String>,
909    audience: Option<String>,
910    token_lifetime: Option<Duration>,
911    refresh_token_lifetime: Option<Duration>,
912    algorithm: Option<crate::config::JwtAlgorithm>,
913}
914
915impl JwtBuilder {
916    fn new(parent: AuthBuilder) -> Self {
917        Self {
918            parent,
919            secret: None,
920            issuer: None,
921            audience: None,
922            token_lifetime: None,
923            refresh_token_lifetime: None,
924            algorithm: None,
925        }
926    }
927
928    /// Set JWT secret key.
929    ///
930    /// Must be at least 32 characters for HMAC algorithms.
931    ///
932    /// # Example
933    ///
934    /// ```rust,no_run
935    /// use auth_framework::prelude::*;
936    ///
937    /// let builder = AuthFramework::builder()
938    ///     .with_jwt().secret("my-long-secret-key-32-chars-min!!").done();
939    /// ```
940    pub fn secret(mut self, secret: impl Into<String>) -> Self {
941        self.secret = Some(secret.into());
942        self
943    }
944
945    /// Set JWT secret from environment variable.
946    ///
947    /// # Example
948    ///
949    /// ```rust,no_run
950    /// use auth_framework::prelude::*;
951    ///
952    /// let builder = AuthFramework::builder()
953    ///     .with_jwt().secret_from_env("MY_JWT_SECRET").done();
954    /// ```
955    pub fn secret_from_env(mut self, env_var: &str) -> Self {
956        if let Ok(secret) = std::env::var(env_var) {
957            self.secret = Some(secret);
958        }
959        self
960    }
961
962    /// Set JWT issuer.
963    ///
964    /// # Example
965    ///
966    /// ```rust,no_run
967    /// use auth_framework::prelude::*;
968    ///
969    /// let builder = AuthFramework::builder()
970    ///     .with_jwt().secret("secret-key-at-least-32-characters!!").issuer("my-service").done();
971    /// ```
972    pub fn issuer(mut self, issuer: impl Into<String>) -> Self {
973        self.issuer = Some(issuer.into());
974        self
975    }
976
977    /// Set JWT audience.
978    ///
979    /// # Example
980    ///
981    /// ```rust,no_run
982    /// use auth_framework::prelude::*;
983    ///
984    /// let builder = AuthFramework::builder()
985    ///     .with_jwt().secret("secret-key-at-least-32-characters!!").audience("my-api").done();
986    /// ```
987    pub fn audience(mut self, audience: impl Into<String>) -> Self {
988        self.audience = Some(audience.into());
989        self
990    }
991
992    /// Set token lifetime.
993    ///
994    /// # Example
995    ///
996    /// ```rust,no_run
997    /// use auth_framework::prelude::*;
998    /// use std::time::Duration;
999    ///
1000    /// let builder = AuthFramework::builder()
1001    ///     .with_jwt()
1002    ///     .secret("secret-key-at-least-32-characters!!")
1003    ///     .token_lifetime(Duration::from_secs(1800))
1004    ///     .done();
1005    /// ```
1006    pub fn token_lifetime(mut self, lifetime: Duration) -> Self {
1007        self.token_lifetime = Some(lifetime);
1008        self
1009    }
1010
1011    /// Set refresh token lifetime (defaults to 7 days).
1012    ///
1013    /// # Example
1014    ///
1015    /// ```rust,no_run
1016    /// use auth_framework::prelude::*;
1017    /// use std::time::Duration;
1018    ///
1019    /// let builder = AuthFramework::builder()
1020    ///     .with_jwt()
1021    ///     .secret("secret-key-at-least-32-characters!!")
1022    ///     .refresh_token_lifetime(Duration::from_secs(86400))
1023    ///     .done();
1024    /// ```
1025    pub fn refresh_token_lifetime(mut self, lifetime: Duration) -> Self {
1026        self.refresh_token_lifetime = Some(lifetime);
1027        self
1028    }
1029
1030    /// Set the JWT signing algorithm (defaults to HS256).
1031    ///
1032    /// # Example
1033    ///
1034    /// ```rust,no_run
1035    /// use auth_framework::prelude::*;
1036    /// use auth_framework::config::JwtAlgorithm;
1037    ///
1038    /// let builder = AuthFramework::builder()
1039    ///     .with_jwt()
1040    ///     .secret("secret-key-at-least-32-characters!!")
1041    ///     .algorithm(JwtAlgorithm::HS512)
1042    ///     .done();
1043    /// ```
1044    pub fn algorithm(mut self, algorithm: crate::config::JwtAlgorithm) -> Self {
1045        self.algorithm = Some(algorithm);
1046        self
1047    }
1048
1049    /// Complete JWT configuration and return to main builder.
1050    ///
1051    /// # Example
1052    ///
1053    /// ```rust,no_run
1054    /// use auth_framework::prelude::*;
1055    ///
1056    /// let builder = AuthFramework::builder()
1057    ///     .with_jwt().secret("secret-key-at-least-32-characters!!").done()
1058    ///     .with_storage().memory().done();
1059    /// ```
1060    pub fn done(mut self) -> AuthBuilder {
1061        if let Some(secret) = self.secret {
1062            self.parent.config.secret = Some(secret);
1063        }
1064        if let Some(issuer) = self.issuer {
1065            self.parent.config.issuer = issuer;
1066        }
1067        if let Some(audience) = self.audience {
1068            self.parent.config.audience = audience;
1069        }
1070        if let Some(lifetime) = self.token_lifetime {
1071            self.parent.config.token_lifetime = lifetime;
1072        }
1073        if let Some(lifetime) = self.refresh_token_lifetime {
1074            self.parent.config.refresh_token_lifetime = lifetime;
1075        }
1076        if let Some(algorithm) = self.algorithm {
1077            self.parent.config.security.jwt_algorithm = algorithm;
1078        }
1079        self.parent
1080    }
1081}
1082
1083/// Sub-builder for OAuth 2.0 client credentials.
1084///
1085/// Entered via [`AuthBuilder::with_oauth2()`]; call [`done()`](OAuth2Builder::done)
1086/// to return to the parent builder.
1087pub struct OAuth2Builder {
1088    parent: AuthBuilder,
1089    client_id: Option<String>,
1090    client_secret: Option<String>,
1091    redirect_uri: Option<String>,
1092}
1093
1094impl OAuth2Builder {
1095    fn new(parent: AuthBuilder) -> Self {
1096        Self {
1097            parent,
1098            client_id: None,
1099            client_secret: None,
1100            redirect_uri: None,
1101        }
1102    }
1103
1104    /// Set OAuth2 client ID.
1105    ///
1106    /// # Example
1107    ///
1108    /// ```rust,no_run
1109    /// use auth_framework::prelude::*;
1110    ///
1111    /// let builder = AuthFramework::builder()
1112    ///     .with_oauth2().client_id("my-client-id").done();
1113    /// ```
1114    pub fn client_id(mut self, client_id: impl Into<String>) -> Self {
1115        self.client_id = Some(client_id.into());
1116        self
1117    }
1118
1119    /// Set OAuth2 client secret.
1120    ///
1121    /// # Example
1122    ///
1123    /// ```rust,no_run
1124    /// use auth_framework::prelude::*;
1125    ///
1126    /// let builder = AuthFramework::builder()
1127    ///     .with_oauth2().client_id("id").client_secret("secret").done();
1128    /// ```
1129    pub fn client_secret(mut self, client_secret: impl Into<String>) -> Self {
1130        self.client_secret = Some(client_secret.into());
1131        self
1132    }
1133
1134    /// Set redirect URI.
1135    ///
1136    /// # Example
1137    ///
1138    /// ```rust,no_run
1139    /// use auth_framework::prelude::*;
1140    ///
1141    /// let builder = AuthFramework::builder()
1142    ///     .with_oauth2()
1143    ///     .client_id("id")
1144    ///     .redirect_uri("https://example.com/callback")
1145    ///     .done();
1146    /// ```
1147    pub fn redirect_uri(mut self, redirect_uri: impl Into<String>) -> Self {
1148        self.redirect_uri = Some(redirect_uri.into());
1149        self
1150    }
1151
1152    /// Configure Google OAuth2.
1153    ///
1154    /// Alias for [`client_id`](Self::client_id).
1155    ///
1156    /// # Example
1157    ///
1158    /// ```rust,no_run
1159    /// use auth_framework::prelude::*;
1160    ///
1161    /// let builder = AuthFramework::builder()
1162    ///     .with_oauth2().google_client_id("123.apps.googleusercontent.com").done();
1163    /// ```
1164    pub fn google_client_id(self, client_id: impl Into<String>) -> Self {
1165        self.client_id(client_id)
1166    }
1167
1168    /// Configure GitHub OAuth2.
1169    ///
1170    /// Alias for [`client_id`](Self::client_id).
1171    ///
1172    /// # Example
1173    ///
1174    /// ```rust,no_run
1175    /// use auth_framework::prelude::*;
1176    ///
1177    /// let builder = AuthFramework::builder()
1178    ///     .with_oauth2().github_client_id("Iv1.abc123").done();
1179    /// ```
1180    pub fn github_client_id(self, client_id: impl Into<String>) -> Self {
1181        self.client_id(client_id)
1182    }
1183
1184    /// Complete OAuth2 configuration and return to main builder.
1185    ///
1186    /// # Example
1187    ///
1188    /// ```rust,no_run
1189    /// use auth_framework::prelude::*;
1190    ///
1191    /// let builder = AuthFramework::builder()
1192    ///     .with_oauth2().client_id("id").client_secret("secret").done();
1193    /// ```
1194    pub fn done(mut self) -> AuthBuilder {
1195        let mut oauth2_config = serde_json::Map::new();
1196        if let Some(client_id) = self.client_id {
1197            oauth2_config.insert(
1198                "client_id".to_string(),
1199                serde_json::Value::String(client_id),
1200            );
1201        }
1202        if let Some(client_secret) = self.client_secret {
1203            oauth2_config.insert(
1204                "client_secret".to_string(),
1205                serde_json::Value::String(client_secret),
1206            );
1207        }
1208        if let Some(redirect_uri) = self.redirect_uri {
1209            oauth2_config.insert(
1210                "redirect_uri".to_string(),
1211                serde_json::Value::String(redirect_uri),
1212            );
1213        }
1214        self.parent.config.method_configs.insert(
1215            "oauth2".to_string(),
1216            serde_json::Value::Object(oauth2_config),
1217        );
1218        self.parent
1219    }
1220}
1221
1222/// Sub-builder for storage backend selection.
1223///
1224/// Entered via [`AuthBuilder::with_storage()`]; call [`done()`](StorageBuilder::done)
1225/// to return to the parent builder.
1226pub struct StorageBuilder {
1227    parent: AuthBuilder,
1228}
1229
1230impl StorageBuilder {
1231    fn new(parent: AuthBuilder) -> Self {
1232        Self { parent }
1233    }
1234
1235    /// Use a custom storage instance (already initialized) instead of
1236    /// the built-in storage backends.
1237    ///
1238    /// Pass any type that implements [`AuthStorage`](crate::storage::AuthStorage)
1239    /// wrapped in an `Arc`. This is the extension point for third-party or
1240    /// proprietary databases (SurrealDB, FoundationDB, DynamoDB, etc.).
1241    ///
1242    /// # Example
1243    ///
1244    /// ```rust,ignore
1245    /// use std::sync::Arc;
1246    /// use auth_framework::prelude::*;
1247    /// use auth_framework::storage::AuthStorage;
1248    ///
1249    /// // Implement `AuthStorage` for your backend, then:
1250    /// let storage: Arc<dyn AuthStorage> = Arc::new(
1251    ///     MySurrealStorage::connect("ws://localhost:8000").await?,
1252    /// );
1253    ///
1254    /// let auth = AuthFramework::builder()
1255    ///     .with_storage()
1256    ///     .custom(storage)
1257    ///     .done()
1258    ///     .build()
1259    ///     .await?;
1260    /// ```
1261    pub fn custom(mut self, storage: std::sync::Arc<dyn crate::storage::AuthStorage>) -> Self {
1262        self.parent.custom_storage = Some(storage);
1263        self
1264    }
1265
1266    /// Configure in-memory storage.
1267    ///
1268    /// # Example
1269    ///
1270    /// ```rust,no_run
1271    /// use auth_framework::prelude::*;
1272    ///
1273    /// let builder = AuthFramework::builder()
1274    ///     .with_storage().memory().done();
1275    /// ```
1276    pub fn memory(mut self) -> Self {
1277        self.parent.config.storage = StorageConfig::Memory;
1278        self
1279    }
1280
1281    /// Configure PostgreSQL storage.
1282    ///
1283    /// # Example
1284    ///
1285    /// ```rust,no_run
1286    /// use auth_framework::prelude::*;
1287    ///
1288    /// let builder = AuthFramework::builder()
1289    ///     .with_storage().postgres("postgresql://user:pass@localhost/db").done();
1290    /// ```
1291    #[cfg(feature = "postgres-storage")]
1292    pub fn postgres(mut self, connection_string: impl Into<String>) -> Self {
1293        self.parent.config.storage = StorageConfig::Postgres {
1294            connection_string: connection_string.into(),
1295            table_prefix: "auth_".to_string(),
1296        };
1297        self
1298    }
1299
1300    /// Configure PostgreSQL storage from environment.
1301    ///
1302    /// Reads `DATABASE_URL` from the environment.
1303    ///
1304    /// # Example
1305    ///
1306    /// ```rust,no_run
1307    /// use auth_framework::prelude::*;
1308    ///
1309    /// let builder = AuthFramework::builder()
1310    ///     .with_storage().postgres_from_env().done();
1311    /// ```
1312    #[cfg(feature = "postgres-storage")]
1313    pub fn postgres_from_env(mut self) -> Self {
1314        if let Ok(conn_str) = std::env::var("DATABASE_URL") {
1315            self = self.postgres(conn_str);
1316        }
1317        self
1318    }
1319
1320    /// Configure Redis storage.
1321    ///
1322    /// # Example
1323    ///
1324    /// ```rust,no_run
1325    /// use auth_framework::prelude::*;
1326    ///
1327    /// let builder = AuthFramework::builder()
1328    ///     .with_storage().redis("redis://localhost:6379").done();
1329    /// ```
1330    #[cfg(feature = "redis-storage")]
1331    pub fn redis(mut self, url: impl Into<String>) -> Self {
1332        self.parent.config.storage = StorageConfig::Redis {
1333            url: url.into(),
1334            key_prefix: "auth:".to_string(),
1335        };
1336        self
1337    }
1338
1339    /// Configure Redis storage from environment.
1340    ///
1341    /// Reads `REDIS_URL` from the environment.
1342    ///
1343    /// # Example
1344    ///
1345    /// ```rust,no_run
1346    /// use auth_framework::prelude::*;
1347    ///
1348    /// let builder = AuthFramework::builder()
1349    ///     .with_storage().redis_from_env().done();
1350    /// ```
1351    #[cfg(feature = "redis-storage")]
1352    pub fn redis_from_env(mut self) -> Self {
1353        if let Ok(url) = std::env::var("REDIS_URL") {
1354            self = self.redis(url);
1355        }
1356        self
1357    }
1358
1359    /// Configure SQLite storage
1360    #[cfg(feature = "sqlite-storage")]
1361    pub fn sqlite(mut self, connection_string: impl Into<String>) -> Self {
1362        self.parent.config.storage = StorageConfig::Sqlite {
1363            connection_string: connection_string.into(),
1364        };
1365        self
1366    }
1367
1368    /// Set connection pool size.
1369    ///
1370    /// # Example
1371    ///
1372    /// ```rust,no_run
1373    /// use auth_framework::prelude::*;
1374    ///
1375    /// let builder = AuthFramework::builder()
1376    ///     .with_storage().memory().connection_pool_size(20).done();
1377    /// ```
1378    pub fn connection_pool_size(mut self, size: u32) -> Self {
1379        self.parent.storage_pool_size = Some(size);
1380        self
1381    }
1382
1383    /// Complete storage configuration and return to main builder.
1384    pub fn done(self) -> AuthBuilder {
1385        self.parent
1386    }
1387}
1388
1389/// Sub-builder for rate limiting policy.
1390///
1391/// Entered via [`AuthBuilder::with_rate_limit()`]; call
1392/// [`done()`](RateLimitBuilder::done) to return to the parent builder.
1393pub struct RateLimitBuilder {
1394    parent: AuthBuilder,
1395}
1396
1397impl RateLimitBuilder {
1398    fn new(parent: AuthBuilder) -> Self {
1399        Self { parent }
1400    }
1401
1402    /// Configure rate limiting per IP.
1403    ///
1404    /// # Example
1405    ///
1406    /// ```rust,no_run
1407    /// use auth_framework::prelude::*;
1408    /// use std::time::Duration;
1409    ///
1410    /// let builder = AuthFramework::builder()
1411    ///     .with_rate_limiting().per_ip((200, Duration::from_secs(60))).done();
1412    /// ```
1413    pub fn per_ip(mut self, (requests, window): (u32, Duration)) -> Self {
1414        self.parent.config.rate_limiting = RateLimitConfig {
1415            enabled: true,
1416            max_requests: requests,
1417            window,
1418            burst: requests / 10,
1419        };
1420        self
1421    }
1422
1423    /// Disable rate limiting.
1424    ///
1425    /// # Example
1426    ///
1427    /// ```rust,no_run
1428    /// use auth_framework::prelude::*;
1429    ///
1430    /// let builder = AuthFramework::builder()
1431    ///     .with_rate_limiting().disabled().done();
1432    /// ```
1433    pub fn disabled(mut self) -> Self {
1434        self.parent.config.rate_limiting.enabled = false;
1435        self
1436    }
1437
1438    /// Complete rate limiting configuration and return to main builder.
1439    pub fn done(self) -> AuthBuilder {
1440        self.parent
1441    }
1442}
1443
1444/// Sub-builder for security settings (passwords, cookies, CSRF).
1445///
1446/// Entered via [`AuthBuilder::with_security()`]; call
1447/// [`done()`](SecurityBuilder::done) to return to the parent builder.
1448pub struct SecurityBuilder {
1449    parent: AuthBuilder,
1450}
1451
1452impl SecurityBuilder {
1453    fn new(parent: AuthBuilder) -> Self {
1454        Self { parent }
1455    }
1456
1457    /// Set minimum password length.
1458    ///
1459    /// # Example
1460    ///
1461    /// ```rust,no_run
1462    /// use auth_framework::prelude::*;
1463    ///
1464    /// let builder = AuthFramework::builder()
1465    ///     .with_security().min_password_length(12).done();
1466    /// ```
1467    pub fn min_password_length(mut self, length: usize) -> Self {
1468        self.parent.config.security.min_password_length = length;
1469        self
1470    }
1471
1472    /// Enable/disable password complexity requirements.
1473    ///
1474    /// # Example
1475    ///
1476    /// ```rust,no_run
1477    /// use auth_framework::prelude::*;
1478    ///
1479    /// let builder = AuthFramework::builder()
1480    ///     .with_security().require_password_complexity(false).done();
1481    /// ```
1482    pub fn require_password_complexity(mut self, required: bool) -> Self {
1483        self.parent.config.security.require_password_complexity = required;
1484        self
1485    }
1486
1487    /// Enable/disable secure cookies.
1488    ///
1489    /// # Example
1490    ///
1491    /// ```rust,no_run
1492    /// use auth_framework::prelude::*;
1493    ///
1494    /// let builder = AuthFramework::builder()
1495    ///     .with_security().secure_cookies(true).done();
1496    /// ```
1497    pub fn secure_cookies(mut self, enabled: bool) -> Self {
1498        self.parent.config.security.secure_cookies = enabled;
1499        self
1500    }
1501
1502    /// Complete security configuration and return to main builder.
1503    pub fn done(self) -> AuthBuilder {
1504        self.parent
1505    }
1506}
1507
1508/// Sub-builder for audit logging settings.
1509///
1510/// Entered via [`AuthBuilder::with_audit()`]; call
1511/// [`done()`](AuditBuilder::done) to return to the parent builder.
1512pub struct AuditBuilder {
1513    parent: AuthBuilder,
1514}
1515
1516impl AuditBuilder {
1517    fn new(parent: AuthBuilder) -> Self {
1518        Self { parent }
1519    }
1520
1521    /// Enable audit logging.
1522    ///
1523    /// # Example
1524    ///
1525    /// ```rust,no_run
1526    /// use auth_framework::prelude::*;
1527    ///
1528    /// let builder = AuthFramework::builder()
1529    ///     .with_audit().enabled(true).done();
1530    /// ```
1531    pub fn enabled(mut self, enabled: bool) -> Self {
1532        self.parent.config.audit.enabled = enabled;
1533        self
1534    }
1535
1536    /// Log successful authentications.
1537    ///
1538    /// # Example
1539    ///
1540    /// ```rust,no_run
1541    /// use auth_framework::prelude::*;
1542    ///
1543    /// let builder = AuthFramework::builder()
1544    ///     .with_audit().log_success(true).done();
1545    /// ```
1546    pub fn log_success(mut self, enabled: bool) -> Self {
1547        self.parent.config.audit.log_success = enabled;
1548        self
1549    }
1550
1551    /// Log failed authentications.
1552    ///
1553    /// # Example
1554    ///
1555    /// ```rust,no_run
1556    /// use auth_framework::prelude::*;
1557    ///
1558    /// let builder = AuthFramework::builder()
1559    ///     .with_audit().log_failures(true).done();
1560    /// ```
1561    pub fn log_failures(mut self, enabled: bool) -> Self {
1562        self.parent.config.audit.log_failures = enabled;
1563        self
1564    }
1565
1566    /// Complete audit configuration and return to main builder.
1567    pub fn done(self) -> AuthBuilder {
1568        self.parent
1569    }
1570}
1571
1572impl Default for AuthBuilder {
1573    fn default() -> Self {
1574        Self::new()
1575    }
1576}