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
63#[derive(Debug)]
65pub struct AuthBuilder {
66 config: AuthConfig,
67 security_preset: Option<SecurityPreset>,
68 performance_preset: Option<PerformancePreset>,
69 use_case_preset: Option<UseCasePreset>,
70}
71
72#[derive(Debug)]
74pub struct QuickStartBuilder {
75 auth_method: Option<QuickStartAuth>,
76 storage: Option<QuickStartStorage>,
77 framework: Option<QuickStartFramework>,
78 security_level: SecurityPreset,
79}
80
81#[derive(Debug)]
83pub enum QuickStartAuth {
84 Jwt {
85 secret: String,
86 },
87 JwtFromEnv,
88 OAuth2 {
89 client_id: String,
90 client_secret: String,
91 },
92 Combined {
93 jwt_secret: String,
94 oauth_client_id: String,
95 oauth_client_secret: String,
96 },
97}
98
99#[derive(Debug)]
101pub enum QuickStartStorage {
102 Memory,
103 Postgres(String),
104 PostgresFromEnv,
105 Redis(String),
106 RedisFromEnv,
107}
108
109#[derive(Debug)]
111pub enum QuickStartFramework {
112 Axum,
113 ActixWeb,
114 Warp,
115}
116
117impl AuthFramework {
118 pub fn builder() -> AuthBuilder {
120 AuthBuilder::new()
121 }
122
123 pub fn quick_start() -> QuickStartBuilder {
125 QuickStartBuilder::new()
126 }
127
128 pub fn for_use_case(use_case: UseCasePreset) -> AuthBuilder {
130 AuthBuilder::new().use_case_preset(use_case)
131 }
132
133 pub fn preset(preset: SecurityPreset) -> AuthBuilder {
135 AuthBuilder::new().security_preset(preset)
136 }
137}
138
139impl AuthBuilder {
140 pub fn new() -> Self {
142 Self {
143 config: AuthConfig::default(),
144 security_preset: None,
145 performance_preset: None,
146 use_case_preset: None,
147 }
148 }
149
150 pub fn security_preset(mut self, preset: SecurityPreset) -> Self {
152 self.security_preset = Some(preset);
153 self
154 }
155
156 pub fn performance_preset(mut self, preset: PerformancePreset) -> Self {
158 self.performance_preset = Some(preset);
159 self
160 }
161
162 pub fn use_case_preset(mut self, preset: UseCasePreset) -> Self {
164 self.use_case_preset = Some(preset);
165 self
166 }
167
168 pub fn with_jwt(self) -> JwtBuilder {
170 JwtBuilder::new(self)
171 }
172
173 pub fn with_oauth2(self) -> OAuth2Builder {
175 OAuth2Builder::new(self)
176 }
177
178 pub fn with_storage(self) -> StorageBuilder {
180 StorageBuilder::new(self)
181 }
182
183 pub fn with_rate_limiting(self) -> RateLimitBuilder {
185 RateLimitBuilder::new(self)
186 }
187
188 pub fn with_security(self) -> SecurityBuilder {
190 SecurityBuilder::new(self)
191 }
192
193 pub fn with_audit(self) -> AuditBuilder {
195 AuditBuilder::new(self)
196 }
197
198 pub fn customize<F>(mut self, f: F) -> Self
200 where
201 F: FnOnce(&mut AuthConfig) -> &mut AuthConfig,
202 {
203 f(&mut self.config);
204 self
205 }
206
207 pub async fn build(mut self) -> Result<AuthFramework, AuthError> {
209 if let Some(preset) = self.security_preset.take() {
211 self.config.security = self.apply_security_preset(preset);
212 }
213
214 if let Some(preset) = self.performance_preset.take() {
215 self.apply_performance_preset(preset);
216 }
217
218 if let Some(preset) = self.use_case_preset.take() {
219 self.apply_use_case_preset(preset);
220 }
221
222 self.config.validate()?;
224
225 let mut framework = AuthFramework::new(self.config);
227 framework.initialize().await?;
228
229 Ok(framework)
230 }
231
232 fn apply_security_preset(&self, preset: SecurityPreset) -> SecurityConfig {
233 match preset {
234 SecurityPreset::Development => SecurityConfig::development(),
235 SecurityPreset::Balanced => SecurityConfig::default(),
236 SecurityPreset::HighSecurity | SecurityPreset::Paranoid => SecurityConfig::secure(),
237 }
238 }
239
240 fn apply_performance_preset(&mut self, preset: PerformancePreset) {
241 match preset {
242 PerformancePreset::HighThroughput => {
243 self.config.rate_limiting.max_requests = 1000;
245 self.config.rate_limiting.window = Duration::from_secs(60);
246 }
247 PerformancePreset::LowLatency => {
248 self.config.token_lifetime = hours(1);
250 self.config.rate_limiting.max_requests = 100;
251 self.config.rate_limiting.window = Duration::from_secs(60);
252 }
253 PerformancePreset::LowMemory => {
254 self.config.token_lifetime = minutes(15);
256 self.config.refresh_token_lifetime = hours(2);
257 }
258 PerformancePreset::Balanced => {
259 }
261 }
262 }
263
264 fn apply_use_case_preset(&mut self, preset: UseCasePreset) {
265 match preset {
266 UseCasePreset::WebApp => {
267 self.config.token_lifetime = hours(24);
268 self.config.refresh_token_lifetime = days(7);
269 self.config.security.secure_cookies = true;
270 self.config.security.csrf_protection = true;
271 }
272 UseCasePreset::ApiService => {
273 self.config.token_lifetime = hours(1);
274 self.config.refresh_token_lifetime = hours(24);
275 self.config.rate_limiting.enabled = true;
276 self.config.rate_limiting.max_requests = 1000;
277 }
278 UseCasePreset::Microservices => {
279 self.config.token_lifetime = minutes(15);
280 self.config.refresh_token_lifetime = hours(1);
281 self.config.audit.enabled = true;
282 }
283 UseCasePreset::MobileBackend => {
284 self.config.token_lifetime = hours(1);
285 self.config.refresh_token_lifetime = days(30);
286 self.config.security.secure_cookies = false; }
288 UseCasePreset::Enterprise => {
289 self.config.enable_multi_factor = true;
290 self.config.security = SecurityConfig::secure();
291 self.config.audit.enabled = true;
292 self.config.audit.log_success = true;
293 self.config.audit.log_failures = true;
294 }
295 }
296 }
297}
298
299impl QuickStartBuilder {
300 fn new() -> Self {
301 Self {
302 auth_method: None,
303 storage: None,
304 framework: None,
305 security_level: SecurityPreset::Balanced,
306 }
307 }
308
309 pub fn jwt_auth(mut self, secret: impl Into<String>) -> Self {
311 self.auth_method = Some(QuickStartAuth::Jwt {
312 secret: secret.into(),
313 });
314 self
315 }
316
317 pub fn jwt_auth_from_env(mut self) -> Self {
319 self.auth_method = Some(QuickStartAuth::JwtFromEnv);
320 self
321 }
322
323 pub fn oauth2_auth(
325 mut self,
326 client_id: impl Into<String>,
327 client_secret: impl Into<String>,
328 ) -> Self {
329 self.auth_method = Some(QuickStartAuth::OAuth2 {
330 client_id: client_id.into(),
331 client_secret: client_secret.into(),
332 });
333 self
334 }
335
336 pub fn combined_auth(
338 mut self,
339 jwt_secret: impl Into<String>,
340 oauth_client_id: impl Into<String>,
341 oauth_client_secret: impl Into<String>,
342 ) -> Self {
343 self.auth_method = Some(QuickStartAuth::Combined {
344 jwt_secret: jwt_secret.into(),
345 oauth_client_id: oauth_client_id.into(),
346 oauth_client_secret: oauth_client_secret.into(),
347 });
348 self
349 }
350
351 pub fn with_postgres(mut self, connection_string: impl Into<String>) -> Self {
353 self.storage = Some(QuickStartStorage::Postgres(connection_string.into()));
354 self
355 }
356
357 pub fn with_postgres_from_env(mut self) -> Self {
359 self.storage = Some(QuickStartStorage::PostgresFromEnv);
360 self
361 }
362
363 pub fn with_redis(mut self, connection_string: impl Into<String>) -> Self {
365 self.storage = Some(QuickStartStorage::Redis(connection_string.into()));
366 self
367 }
368
369 pub fn with_redis_from_env(mut self) -> Self {
371 self.storage = Some(QuickStartStorage::RedisFromEnv);
372 self
373 }
374
375 pub fn with_memory_storage(mut self) -> Self {
377 self.storage = Some(QuickStartStorage::Memory);
378 self
379 }
380
381 pub fn with_axum(mut self) -> Self {
383 self.framework = Some(QuickStartFramework::Axum);
384 self
385 }
386
387 pub fn with_actix(mut self) -> Self {
389 self.framework = Some(QuickStartFramework::ActixWeb);
390 self
391 }
392
393 pub fn with_warp(mut self) -> Self {
395 self.framework = Some(QuickStartFramework::Warp);
396 self
397 }
398
399 pub fn security_level(mut self, level: SecurityPreset) -> Self {
401 self.security_level = level;
402 self
403 }
404
405 pub async fn build(self) -> Result<AuthFramework, AuthError> {
407 let mut builder = AuthBuilder::new().security_preset(self.security_level);
408
409 match self.auth_method {
411 Some(QuickStartAuth::Jwt { secret }) => {
412 builder = builder.with_jwt().secret(secret).done();
413 }
414 Some(QuickStartAuth::JwtFromEnv) => {
415 let secret = std::env::var("JWT_SECRET").map_err(|_| {
416 AuthError::config("JWT_SECRET environment variable is required")
417 })?;
418 builder = builder.with_jwt().secret(secret).done();
419 }
420 Some(QuickStartAuth::OAuth2 {
421 client_id,
422 client_secret,
423 }) => {
424 builder = builder
425 .with_oauth2()
426 .client_id(client_id)
427 .client_secret(client_secret)
428 .done();
429 }
430 Some(QuickStartAuth::Combined {
431 jwt_secret,
432 oauth_client_id,
433 oauth_client_secret,
434 }) => {
435 builder = builder
436 .with_jwt()
437 .secret(jwt_secret)
438 .done()
439 .with_oauth2()
440 .client_id(oauth_client_id)
441 .client_secret(oauth_client_secret)
442 .done();
443 }
444 None => {
445 return Err(AuthError::config("Authentication method is required"));
446 }
447 }
448
449 match self.storage {
451 Some(QuickStartStorage::Memory) => {
452 builder = builder.with_storage().memory().done();
453 }
454 Some(QuickStartStorage::Postgres(conn_str)) => {
455 builder = builder.with_storage().postgres(conn_str).done();
456 }
457 Some(QuickStartStorage::PostgresFromEnv) => {
458 let conn_str = std::env::var("DATABASE_URL").map_err(|_| {
459 AuthError::config("DATABASE_URL environment variable is required")
460 })?;
461 builder = builder.with_storage().postgres(conn_str).done();
462 }
463 Some(QuickStartStorage::Redis(_conn_str)) => {
464 builder = builder.with_storage().memory().done();
466 }
467 Some(QuickStartStorage::RedisFromEnv) => {
468 builder = builder.with_storage().memory().done();
470 }
471 None => {
472 builder = builder.with_storage().memory().done();
474 }
475 }
476
477 builder.build().await
478 }
479}
480
481pub struct JwtBuilder {
483 parent: AuthBuilder,
484 secret: Option<String>,
485 issuer: Option<String>,
486 audience: Option<String>,
487 token_lifetime: Option<Duration>,
488}
489
490impl JwtBuilder {
491 fn new(parent: AuthBuilder) -> Self {
492 Self {
493 parent,
494 secret: None,
495 issuer: None,
496 audience: None,
497 token_lifetime: None,
498 }
499 }
500
501 pub fn secret(mut self, secret: impl Into<String>) -> Self {
503 self.secret = Some(secret.into());
504 self
505 }
506
507 pub fn secret_from_env(mut self, env_var: &str) -> Self {
509 if let Ok(secret) = std::env::var(env_var) {
510 self.secret = Some(secret);
511 }
512 self
513 }
514
515 pub fn issuer(mut self, issuer: impl Into<String>) -> Self {
517 self.issuer = Some(issuer.into());
518 self
519 }
520
521 pub fn audience(mut self, audience: impl Into<String>) -> Self {
523 self.audience = Some(audience.into());
524 self
525 }
526
527 pub fn token_lifetime(mut self, lifetime: Duration) -> Self {
529 self.token_lifetime = Some(lifetime);
530 self
531 }
532
533 pub fn done(mut self) -> AuthBuilder {
535 if let Some(secret) = self.secret {
536 self.parent.config.secret = Some(secret);
537 }
538 if let Some(issuer) = self.issuer {
539 self.parent.config.issuer = issuer;
540 }
541 if let Some(audience) = self.audience {
542 self.parent.config.audience = audience;
543 }
544 if let Some(lifetime) = self.token_lifetime {
545 self.parent.config.token_lifetime = lifetime;
546 }
547 self.parent
548 }
549}
550
551pub struct OAuth2Builder {
553 parent: AuthBuilder,
554 client_id: Option<String>,
555 client_secret: Option<String>,
556 redirect_uri: Option<String>,
557}
558
559impl OAuth2Builder {
560 fn new(parent: AuthBuilder) -> Self {
561 Self {
562 parent,
563 client_id: None,
564 client_secret: None,
565 redirect_uri: None,
566 }
567 }
568
569 pub fn client_id(mut self, client_id: impl Into<String>) -> Self {
571 self.client_id = Some(client_id.into());
572 self
573 }
574
575 pub fn client_secret(mut self, client_secret: impl Into<String>) -> Self {
577 self.client_secret = Some(client_secret.into());
578 self
579 }
580
581 pub fn redirect_uri(mut self, redirect_uri: impl Into<String>) -> Self {
583 self.redirect_uri = Some(redirect_uri.into());
584 self
585 }
586
587 pub fn google_client_id(self, client_id: impl Into<String>) -> Self {
589 self.client_id(client_id)
590 }
591
592 pub fn github_client_id(self, client_id: impl Into<String>) -> Self {
594 self.client_id(client_id)
595 }
596
597 pub fn done(self) -> AuthBuilder {
599 self.parent
602 }
603}
604
605pub struct StorageBuilder {
607 parent: AuthBuilder,
608}
609
610impl StorageBuilder {
611 fn new(parent: AuthBuilder) -> Self {
612 Self { parent }
613 }
614
615 pub fn memory(mut self) -> Self {
617 self.parent.config.storage = StorageConfig::Memory;
618 self
619 }
620
621 #[cfg(feature = "postgres-storage")]
623 pub fn postgres(mut self, connection_string: impl Into<String>) -> Self {
624 self.parent.config.storage = StorageConfig::Postgres {
625 connection_string: connection_string.into(),
626 table_prefix: "auth_".to_string(),
627 };
628 self
629 }
630
631 #[cfg(feature = "postgres-storage")]
633 pub fn postgres_from_env(mut self) -> Self {
634 if let Ok(conn_str) = std::env::var("DATABASE_URL") {
635 self = self.postgres(conn_str);
636 }
637 self
638 }
639
640 #[cfg(feature = "redis-storage")]
642 pub fn redis(mut self, url: impl Into<String>) -> Self {
643 self.parent.config.storage = StorageConfig::Redis {
644 url: url.into(),
645 key_prefix: "auth:".to_string(),
646 };
647 self
648 }
649
650 #[cfg(feature = "redis-storage")]
652 pub fn redis_from_env(mut self) -> Self {
653 if let Ok(url) = std::env::var("REDIS_URL") {
654 self = self.redis(url);
655 }
656 self
657 }
658
659 pub fn connection_pool_size(self, _size: u32) -> Self {
661 self
663 }
664
665 pub fn done(self) -> AuthBuilder {
667 self.parent
668 }
669}
670
671pub struct RateLimitBuilder {
673 parent: AuthBuilder,
674}
675
676impl RateLimitBuilder {
677 fn new(parent: AuthBuilder) -> Self {
678 Self { parent }
679 }
680
681 pub fn per_ip(mut self, (requests, window): (u32, Duration)) -> Self {
683 self.parent.config.rate_limiting = RateLimitConfig {
684 enabled: true,
685 max_requests: requests,
686 window,
687 burst: requests / 10,
688 };
689 self
690 }
691
692 pub fn disabled(mut self) -> Self {
694 self.parent.config.rate_limiting.enabled = false;
695 self
696 }
697
698 pub fn done(self) -> AuthBuilder {
700 self.parent
701 }
702}
703
704pub struct SecurityBuilder {
706 parent: AuthBuilder,
707}
708
709impl SecurityBuilder {
710 fn new(parent: AuthBuilder) -> Self {
711 Self { parent }
712 }
713
714 pub fn min_password_length(mut self, length: usize) -> Self {
716 self.parent.config.security.min_password_length = length;
717 self
718 }
719
720 pub fn require_password_complexity(mut self, required: bool) -> Self {
722 self.parent.config.security.require_password_complexity = required;
723 self
724 }
725
726 pub fn secure_cookies(mut self, enabled: bool) -> Self {
728 self.parent.config.security.secure_cookies = enabled;
729 self
730 }
731
732 pub fn done(self) -> AuthBuilder {
734 self.parent
735 }
736}
737
738pub struct AuditBuilder {
740 parent: AuthBuilder,
741}
742
743impl AuditBuilder {
744 fn new(parent: AuthBuilder) -> Self {
745 Self { parent }
746 }
747
748 pub fn enabled(mut self, enabled: bool) -> Self {
750 self.parent.config.audit.enabled = enabled;
751 self
752 }
753
754 pub fn log_success(mut self, enabled: bool) -> Self {
756 self.parent.config.audit.log_success = enabled;
757 self
758 }
759
760 pub fn log_failures(mut self, enabled: bool) -> Self {
762 self.parent.config.audit.log_failures = enabled;
763 self
764 }
765
766 pub fn done(self) -> AuthBuilder {
768 self.parent
769 }
770}
771
772impl Default for AuthBuilder {
773 fn default() -> Self {
774 Self::new()
775 }
776}