# OAuth2 STS SOLID Refactoring Plan ## Overview This document outlines refactoring opportunities to better align with SOLID principles. ## 1. Extract Grant Type Handlers (SRP + OCP) ### Current Issue `OAuthServer::handle_token()` contains all grant type logic in one method. ### Proposed Solution ```rust trait GrantHandler { fn can_handle(&self, grant_type: &str) -> bool; fn handle_grant( &self, params: &HashMap, auth_header: Option<&str>, ip_address: Option, ) -> Result; } struct AuthorizationCodeGrantHandler { client_authenticator: Arc, token_generator: Arc, code_repository: Arc, token_repository: Arc, audit_logger: Arc, } struct RefreshTokenGrantHandler { // Similar dependencies } struct GrantHandlerRegistry { handlers: Vec>, } ``` ### Benefits - ✅ Easy to add new grant types (Client Credentials, Device Code, etc.) - ✅ Each handler has single responsibility - ✅ Testable in isolation ## 2. Create Repository Abstractions (DIP + SRP) ### Current Issue Monolithic `Database` struct violates SRP and makes testing difficult. ### Proposed Solution ```rust trait ClientRepository { fn get_client(&self, client_id: &str) -> Result>; fn authenticate_client(&self, client_id: &str, secret: &str) -> Result; fn is_redirect_uri_valid(&self, client_id: &str, uri: &str) -> bool; } trait TokenRepository { fn create_access_token(&self, token: &DbAccessToken) -> Result<()>; fn get_access_token(&self, token_hash: &str) -> Result>; fn revoke_access_token(&self, token_hash: &str) -> Result<()>; } trait AuthCodeRepository { fn create_auth_code(&self, code: &DbAuthCode) -> Result<()>; fn get_auth_code(&self, code: &str) -> Result>; fn mark_auth_code_used(&self, code: &str) -> Result<()>; } // SQLite implementations struct SqliteClientRepository { database: Arc>, } struct SqliteTokenRepository { database: Arc>, } ``` ### Benefits - ✅ Easy to swap database backends (PostgreSQL, Redis, etc.) - ✅ Better testability with mock repositories - ✅ Clear separation of concerns ## 3. Extract Authentication Strategy (OCP + SRP) ### Current Issue Client authentication logic scattered throughout token handlers. ### Proposed Solution ```rust trait ClientAuthenticator { fn authenticate( &self, params: &HashMap, auth_header: Option<&str>, ) -> Result<(String, String), String>; // Returns (client_id, client_secret) } struct BasicAuthenticator { client_repository: Arc, } struct PostAuthenticator { client_repository: Arc, } struct CompositeAuthenticator { authenticators: Vec>, } ``` ### Benefits - ✅ Easy to add new authentication methods (JWT, mTLS, etc.) - ✅ Clear separation of authentication concerns - ✅ Configurable authentication strategies ## 4. Extract Token Generation (SRP + OCP) ### Current Issue Token generation logic embedded in `OAuthServer`. ### Proposed Solution ```rust trait TokenGenerator { fn generate_access_token( &self, user_id: &str, client_id: &str, scope: &Option, token_id: &str, ) -> Result; fn generate_refresh_token( &self, client_id: &str, user_id: &str, scope: &Option, ) -> Result; } struct JwtTokenGenerator { key_manager: Arc>, config: Config, } struct OpaqueTokenGenerator { // For opaque token implementation } ``` ### Benefits - ✅ Easy to switch token formats (JWT vs opaque) - ✅ Configurable token generation strategies - ✅ Better testability ## 5. Extract Cross-Cutting Concerns ### Rate Limiting ```rust trait RateLimiter { fn check_rate_limit(&self, identifier: &str, endpoint: &str) -> Result<()>; } struct DatabaseRateLimiter { rate_repository: Arc, config: Config, } struct RedisRateLimiter { redis_client: redis::Client, config: Config, } ``` ### Audit Logging ```rust trait AuditLogger { fn log_event(&self, event: AuditEvent) -> Result<()>; } struct DatabaseAuditLogger { audit_repository: Arc, } struct JsonFileAuditLogger { file_path: PathBuf, } ``` ## 6. Refactor HTTP Layer (SRP) ### Current Issue `Server` mixes HTTP protocol with OAuth business logic. ### Proposed Solution ```rust struct HttpServer { router: Router, config: Config, } struct Router { oauth_handler: Arc, static_handler: Arc, } struct OAuthHandler { oauth_service: Arc, // Renamed from OAuthServer } // Clean separation between HTTP concerns and OAuth business logic ``` ## 7. Dependency Injection Container ### Proposed Solution ```rust struct ServiceContainer { // Repositories client_repository: Arc, token_repository: Arc, auth_code_repository: Arc, // Services client_authenticator: Arc, token_generator: Arc, rate_limiter: Arc, audit_logger: Arc, // Grant handlers grant_registry: Arc, } impl ServiceContainer { fn new(config: &Config) -> Result { // Wire up all dependencies } } ``` ## Implementation Strategy ### Phase 1: Repository Extraction 1. Create repository traits 2. Move database methods to specific repositories 3. Update `OAuthServer` to use repositories ### Phase 2: Grant Handler Extraction 1. Create `GrantHandler` trait 2. Extract authorization code handler 3. Extract refresh token handler 4. Create registry ### Phase 3: Cross-Cutting Concerns 1. Extract rate limiting 2. Extract audit logging 3. Extract authentication ### Phase 4: HTTP Layer Cleanup 1. Separate HTTP protocol from business logic 2. Create clean request/response handlers ### Phase 5: Dependency Injection 1. Create service container 2. Wire up all dependencies 3. Update main.rs to use container ## Benefits of This Refactoring ### Maintainability - ✅ Easier to understand and modify individual components - ✅ Clear separation of concerns - ✅ Reduced coupling between components ### Extensibility - ✅ Easy to add new grant types - ✅ Easy to swap implementations (database, token format, etc.) - ✅ Configurable strategies for cross-cutting concerns ### Testability - ✅ Each component can be tested in isolation - ✅ Easy to create mock implementations - ✅ Better unit test coverage ### Production Readiness - ✅ Easy to scale different components independently - ✅ Better observability and monitoring capabilities - ✅ More flexible deployment options