1use crate::{
56 AuthConfig, AuthError, AuthFramework,
57 config::{RateLimitConfig, SecurityConfig, StorageConfig},
58 prelude::{PerformancePreset, UseCasePreset, days, hours, minutes},
59 security::SecurityPreset,
60};
61use std::time::Duration;
62
63pub struct AuthBuilder {
65 config: AuthConfig,
66 security_preset: Option<SecurityPreset>,
67 performance_preset: Option<PerformancePreset>,
68 use_case_preset: Option<UseCasePreset>,
69 custom_storage: Option<std::sync::Arc<dyn crate::storage::AuthStorage>>,
71}
72
73#[derive(Debug)]
75pub struct QuickStartBuilder {
76 auth_method: Option<QuickStartAuth>,
77 storage: Option<QuickStartStorage>,
78 framework: Option<QuickStartFramework>,
79 security_level: SecurityPreset,
80}
81
82#[derive(Debug)]
84pub enum QuickStartAuth {
85 Jwt {
86 secret: String,
87 },
88 JwtFromEnv,
89 OAuth2 {
90 client_id: String,
91 client_secret: String,
92 },
93 Combined {
94 jwt_secret: String,
95 oauth_client_id: String,
96 oauth_client_secret: String,
97 },
98}
99
100#[derive(Debug)]
102pub enum QuickStartStorage {
103 Memory,
104 Postgres(String),
105 PostgresFromEnv,
106 Redis(String),
107 RedisFromEnv,
108}
109
110#[derive(Debug)]
112pub enum QuickStartFramework {
113 Axum,
114 ActixWeb,
115 Warp,
116}
117
118impl AuthFramework {
119 pub fn builder() -> AuthBuilder {
121 AuthBuilder::new()
122 }
123
124 pub fn quick_start() -> QuickStartBuilder {
126 QuickStartBuilder::new()
127 }
128
129 pub fn for_use_case(use_case: UseCasePreset) -> AuthBuilder {
131 AuthBuilder::new().use_case_preset(use_case)
132 }
133
134 pub fn preset(preset: SecurityPreset) -> AuthBuilder {
136 AuthBuilder::new().security_preset(preset)
137 }
138}
139
140impl AuthBuilder {
141 pub fn new() -> Self {
143 Self {
144 config: AuthConfig::default(),
145 security_preset: None,
146 performance_preset: None,
147 use_case_preset: None,
148 custom_storage: None,
149 }
150 }
151
152 pub fn security_preset(mut self, preset: SecurityPreset) -> Self {
154 self.security_preset = Some(preset);
155 self
156 }
157
158 pub fn performance_preset(mut self, preset: PerformancePreset) -> Self {
160 self.performance_preset = Some(preset);
161 self
162 }
163
164 pub fn use_case_preset(mut self, preset: UseCasePreset) -> Self {
166 self.use_case_preset = Some(preset);
167 self
168 }
169
170 pub fn with_jwt(self) -> JwtBuilder {
172 JwtBuilder::new(self)
173 }
174
175 pub fn with_oauth2(self) -> OAuth2Builder {
177 OAuth2Builder::new(self)
178 }
179
180 pub fn with_storage(self) -> StorageBuilder {
182 StorageBuilder::new(self)
183 }
184
185 pub fn with_rate_limiting(self) -> RateLimitBuilder {
187 RateLimitBuilder::new(self)
188 }
189
190 pub fn with_security(self) -> SecurityBuilder {
192 SecurityBuilder::new(self)
193 }
194
195 pub fn with_audit(self) -> AuditBuilder {
197 AuditBuilder::new(self)
198 }
199
200 pub fn customize<F>(mut self, f: F) -> Self
202 where
203 F: FnOnce(&mut AuthConfig) -> &mut AuthConfig,
204 {
205 f(&mut self.config);
206 self
207 }
208
209 pub async fn build(mut self) -> Result<AuthFramework, AuthError> {
211 if let Some(preset) = self.security_preset.take() {
213 self.config.security = self.apply_security_preset(preset);
214 }
215
216 if let Some(preset) = self.performance_preset.take() {
217 self.apply_performance_preset(preset);
218 }
219
220 if let Some(preset) = self.use_case_preset.take() {
221 self.apply_use_case_preset(preset);
222 }
223
224 self.config.validate()?;
226
227 let mut framework = AuthFramework::new(self.config);
231 if let Some(storage) = self.custom_storage.take() {
232 framework.replace_storage(storage);
233 }
234 framework.initialize().await?;
235
236 Ok(framework)
237 }
238
239 fn apply_security_preset(&self, preset: SecurityPreset) -> SecurityConfig {
240 match preset {
241 SecurityPreset::Development => SecurityConfig::development(),
242 SecurityPreset::Balanced => SecurityConfig::default(),
243 SecurityPreset::HighSecurity | SecurityPreset::Paranoid => SecurityConfig::secure(),
244 }
245 }
246
247 fn apply_performance_preset(&mut self, preset: PerformancePreset) {
248 match preset {
249 PerformancePreset::HighThroughput => {
250 self.config.rate_limiting.max_requests = 1000;
252 self.config.rate_limiting.window = Duration::from_secs(60);
253 }
254 PerformancePreset::LowLatency => {
255 self.config.token_lifetime = hours(1);
257 self.config.rate_limiting.max_requests = 100;
258 self.config.rate_limiting.window = Duration::from_secs(60);
259 }
260 PerformancePreset::LowMemory => {
261 self.config.token_lifetime = minutes(15);
263 self.config.refresh_token_lifetime = hours(2);
264 }
265 PerformancePreset::Balanced => {
266 }
268 }
269 }
270
271 fn apply_use_case_preset(&mut self, preset: UseCasePreset) {
272 match preset {
273 UseCasePreset::WebApp => {
274 self.config.token_lifetime = hours(24);
275 self.config.refresh_token_lifetime = days(7);
276 self.config.security.secure_cookies = true;
277 self.config.security.csrf_protection = true;
278 }
279 UseCasePreset::ApiService => {
280 self.config.token_lifetime = hours(1);
281 self.config.refresh_token_lifetime = hours(24);
282 self.config.rate_limiting.enabled = true;
283 self.config.rate_limiting.max_requests = 1000;
284 }
285 UseCasePreset::Microservices => {
286 self.config.token_lifetime = minutes(15);
287 self.config.refresh_token_lifetime = hours(1);
288 self.config.audit.enabled = true;
289 }
290 UseCasePreset::MobileBackend => {
291 self.config.token_lifetime = hours(1);
292 self.config.refresh_token_lifetime = days(30);
293 self.config.security.secure_cookies = false; }
295 UseCasePreset::Enterprise => {
296 self.config.enable_multi_factor = true;
297 self.config.security = SecurityConfig::secure();
298 self.config.audit.enabled = true;
299 self.config.audit.log_success = true;
300 self.config.audit.log_failures = true;
301 }
302 }
303 }
304}
305
306impl QuickStartBuilder {
307 fn new() -> Self {
308 Self {
309 auth_method: None,
310 storage: None,
311 framework: None,
312 security_level: SecurityPreset::Balanced,
313 }
314 }
315
316 pub fn jwt_auth(mut self, secret: impl Into<String>) -> Self {
318 self.auth_method = Some(QuickStartAuth::Jwt {
319 secret: secret.into(),
320 });
321 self
322 }
323
324 pub fn jwt_auth_from_env(mut self) -> Self {
326 self.auth_method = Some(QuickStartAuth::JwtFromEnv);
327 self
328 }
329
330 pub fn oauth2_auth(
332 mut self,
333 client_id: impl Into<String>,
334 client_secret: impl Into<String>,
335 ) -> Self {
336 self.auth_method = Some(QuickStartAuth::OAuth2 {
337 client_id: client_id.into(),
338 client_secret: client_secret.into(),
339 });
340 self
341 }
342
343 pub fn combined_auth(
345 mut self,
346 jwt_secret: impl Into<String>,
347 oauth_client_id: impl Into<String>,
348 oauth_client_secret: impl Into<String>,
349 ) -> Self {
350 self.auth_method = Some(QuickStartAuth::Combined {
351 jwt_secret: jwt_secret.into(),
352 oauth_client_id: oauth_client_id.into(),
353 oauth_client_secret: oauth_client_secret.into(),
354 });
355 self
356 }
357
358 pub fn with_postgres(mut self, connection_string: impl Into<String>) -> Self {
360 self.storage = Some(QuickStartStorage::Postgres(connection_string.into()));
361 self
362 }
363
364 pub fn with_postgres_from_env(mut self) -> Self {
366 self.storage = Some(QuickStartStorage::PostgresFromEnv);
367 self
368 }
369
370 pub fn with_redis(mut self, connection_string: impl Into<String>) -> Self {
372 self.storage = Some(QuickStartStorage::Redis(connection_string.into()));
373 self
374 }
375
376 pub fn with_redis_from_env(mut self) -> Self {
378 self.storage = Some(QuickStartStorage::RedisFromEnv);
379 self
380 }
381
382 pub fn with_memory_storage(mut self) -> Self {
384 self.storage = Some(QuickStartStorage::Memory);
385 self
386 }
387
388 pub fn with_axum(mut self) -> Self {
390 self.framework = Some(QuickStartFramework::Axum);
391 self
392 }
393
394 pub fn with_actix(mut self) -> Self {
396 self.framework = Some(QuickStartFramework::ActixWeb);
397 self
398 }
399
400 pub fn with_warp(mut self) -> Self {
402 self.framework = Some(QuickStartFramework::Warp);
403 self
404 }
405
406 pub fn security_level(mut self, level: SecurityPreset) -> Self {
408 self.security_level = level;
409 self
410 }
411
412 pub async fn build(self) -> Result<AuthFramework, AuthError> {
414 let mut builder = AuthBuilder::new().security_preset(self.security_level);
415
416 match self.auth_method {
418 Some(QuickStartAuth::Jwt { secret }) => {
419 builder = builder.with_jwt().secret(secret).done();
420 }
421 Some(QuickStartAuth::JwtFromEnv) => {
422 let secret = std::env::var("JWT_SECRET").map_err(|_| {
423 AuthError::config("JWT_SECRET environment variable is required")
424 })?;
425 builder = builder.with_jwt().secret(secret).done();
426 }
427 Some(QuickStartAuth::OAuth2 {
428 client_id,
429 client_secret,
430 }) => {
431 builder = builder
432 .with_oauth2()
433 .client_id(client_id)
434 .client_secret(client_secret)
435 .done();
436 }
437 Some(QuickStartAuth::Combined {
438 jwt_secret,
439 oauth_client_id,
440 oauth_client_secret,
441 }) => {
442 builder = builder
443 .with_jwt()
444 .secret(jwt_secret)
445 .done()
446 .with_oauth2()
447 .client_id(oauth_client_id)
448 .client_secret(oauth_client_secret)
449 .done();
450 }
451 None => {
452 return Err(AuthError::config("Authentication method is required"));
453 }
454 }
455
456 match self.storage {
458 Some(QuickStartStorage::Memory) => {
459 builder = builder.with_storage().memory().done();
460 }
461 Some(QuickStartStorage::Postgres(conn_str)) => {
462 builder = builder.with_storage().postgres(conn_str).done();
463 }
464 Some(QuickStartStorage::PostgresFromEnv) => {
465 let conn_str = std::env::var("DATABASE_URL").map_err(|_| {
466 AuthError::config("DATABASE_URL environment variable is required")
467 })?;
468 builder = builder.with_storage().postgres(conn_str).done();
469 }
470 Some(QuickStartStorage::Redis(_conn_str)) => {
471 builder = builder.with_storage().memory().done();
473 }
474 Some(QuickStartStorage::RedisFromEnv) => {
475 builder = builder.with_storage().memory().done();
477 }
478 None => {
479 builder = builder.with_storage().memory().done();
481 }
482 }
483
484 builder.build().await
485 }
486}
487
488pub struct JwtBuilder {
490 parent: AuthBuilder,
491 secret: Option<String>,
492 issuer: Option<String>,
493 audience: Option<String>,
494 token_lifetime: Option<Duration>,
495}
496
497impl JwtBuilder {
498 fn new(parent: AuthBuilder) -> Self {
499 Self {
500 parent,
501 secret: None,
502 issuer: None,
503 audience: None,
504 token_lifetime: None,
505 }
506 }
507
508 pub fn secret(mut self, secret: impl Into<String>) -> Self {
510 self.secret = Some(secret.into());
511 self
512 }
513
514 pub fn secret_from_env(mut self, env_var: &str) -> Self {
516 if let Ok(secret) = std::env::var(env_var) {
517 self.secret = Some(secret);
518 }
519 self
520 }
521
522 pub fn issuer(mut self, issuer: impl Into<String>) -> Self {
524 self.issuer = Some(issuer.into());
525 self
526 }
527
528 pub fn audience(mut self, audience: impl Into<String>) -> Self {
530 self.audience = Some(audience.into());
531 self
532 }
533
534 pub fn token_lifetime(mut self, lifetime: Duration) -> Self {
536 self.token_lifetime = Some(lifetime);
537 self
538 }
539
540 pub fn done(mut self) -> AuthBuilder {
542 if let Some(secret) = self.secret {
543 self.parent.config.secret = Some(secret);
544 }
545 if let Some(issuer) = self.issuer {
546 self.parent.config.issuer = issuer;
547 }
548 if let Some(audience) = self.audience {
549 self.parent.config.audience = audience;
550 }
551 if let Some(lifetime) = self.token_lifetime {
552 self.parent.config.token_lifetime = lifetime;
553 }
554 self.parent
555 }
556}
557
558pub struct OAuth2Builder {
560 parent: AuthBuilder,
561 client_id: Option<String>,
562 client_secret: Option<String>,
563 redirect_uri: Option<String>,
564}
565
566impl OAuth2Builder {
567 fn new(parent: AuthBuilder) -> Self {
568 Self {
569 parent,
570 client_id: None,
571 client_secret: None,
572 redirect_uri: None,
573 }
574 }
575
576 pub fn client_id(mut self, client_id: impl Into<String>) -> Self {
578 self.client_id = Some(client_id.into());
579 self
580 }
581
582 pub fn client_secret(mut self, client_secret: impl Into<String>) -> Self {
584 self.client_secret = Some(client_secret.into());
585 self
586 }
587
588 pub fn redirect_uri(mut self, redirect_uri: impl Into<String>) -> Self {
590 self.redirect_uri = Some(redirect_uri.into());
591 self
592 }
593
594 pub fn google_client_id(self, client_id: impl Into<String>) -> Self {
596 self.client_id(client_id)
597 }
598
599 pub fn github_client_id(self, client_id: impl Into<String>) -> Self {
601 self.client_id(client_id)
602 }
603
604 pub fn done(self) -> AuthBuilder {
606 self.parent
609 }
610}
611
612pub struct StorageBuilder {
614 parent: AuthBuilder,
615}
616
617impl StorageBuilder {
618 fn new(parent: AuthBuilder) -> Self {
619 Self { parent }
620 }
621
622 pub fn custom(mut self, storage: std::sync::Arc<dyn crate::storage::AuthStorage>) -> Self {
634 self.parent.custom_storage = Some(storage);
635 self
636 }
637
638 pub fn memory(mut self) -> Self {
640 self.parent.config.storage = StorageConfig::Memory;
641 self
642 }
643
644 #[cfg(feature = "postgres-storage")]
646 pub fn postgres(mut self, connection_string: impl Into<String>) -> Self {
647 self.parent.config.storage = StorageConfig::Postgres {
648 connection_string: connection_string.into(),
649 table_prefix: "auth_".to_string(),
650 };
651 self
652 }
653
654 #[cfg(feature = "postgres-storage")]
656 pub fn postgres_from_env(mut self) -> Self {
657 if let Ok(conn_str) = std::env::var("DATABASE_URL") {
658 self = self.postgres(conn_str);
659 }
660 self
661 }
662
663 #[cfg(feature = "redis-storage")]
665 pub fn redis(mut self, url: impl Into<String>) -> Self {
666 self.parent.config.storage = StorageConfig::Redis {
667 url: url.into(),
668 key_prefix: "auth:".to_string(),
669 };
670 self
671 }
672
673 #[cfg(feature = "redis-storage")]
675 pub fn redis_from_env(mut self) -> Self {
676 if let Ok(url) = std::env::var("REDIS_URL") {
677 self = self.redis(url);
678 }
679 self
680 }
681
682 pub fn connection_pool_size(self, _size: u32) -> Self {
684 self
686 }
687
688 pub fn done(self) -> AuthBuilder {
690 self.parent
691 }
692}
693
694pub struct RateLimitBuilder {
696 parent: AuthBuilder,
697}
698
699impl RateLimitBuilder {
700 fn new(parent: AuthBuilder) -> Self {
701 Self { parent }
702 }
703
704 pub fn per_ip(mut self, (requests, window): (u32, Duration)) -> Self {
706 self.parent.config.rate_limiting = RateLimitConfig {
707 enabled: true,
708 max_requests: requests,
709 window,
710 burst: requests / 10,
711 per_user_enabled: false,
712 max_requests_per_user: requests,
713 per_user_window: window,
714 };
715 self
716 }
717
718 pub fn disabled(mut self) -> Self {
720 self.parent.config.rate_limiting.enabled = false;
721 self
722 }
723
724 pub fn done(self) -> AuthBuilder {
726 self.parent
727 }
728}
729
730pub struct SecurityBuilder {
732 parent: AuthBuilder,
733}
734
735impl SecurityBuilder {
736 fn new(parent: AuthBuilder) -> Self {
737 Self { parent }
738 }
739
740 pub fn min_password_length(mut self, length: usize) -> Self {
742 self.parent.config.security.min_password_length = length;
743 self
744 }
745
746 pub fn require_password_complexity(mut self, required: bool) -> Self {
748 self.parent.config.security.require_password_complexity = required;
749 self
750 }
751
752 pub fn secure_cookies(mut self, enabled: bool) -> Self {
754 self.parent.config.security.secure_cookies = enabled;
755 self
756 }
757
758 pub fn done(self) -> AuthBuilder {
760 self.parent
761 }
762}
763
764pub struct AuditBuilder {
766 parent: AuthBuilder,
767}
768
769impl AuditBuilder {
770 fn new(parent: AuthBuilder) -> Self {
771 Self { parent }
772 }
773
774 pub fn enabled(mut self, enabled: bool) -> Self {
776 self.parent.config.audit.enabled = enabled;
777 self
778 }
779
780 pub fn log_success(mut self, enabled: bool) -> Self {
782 self.parent.config.audit.log_success = enabled;
783 self
784 }
785
786 pub fn log_failures(mut self, enabled: bool) -> Self {
788 self.parent.config.audit.log_failures = enabled;
789 self
790 }
791
792 pub fn done(self) -> AuthBuilder {
794 self.parent
795 }
796}
797
798impl Default for AuthBuilder {
799 fn default() -> Self {
800 Self::new()
801 }
802}