# Authorization Package This package provides JWT-based authorization services for the Tender Management system, following Clean Architecture principles and best practices. ## Features - **JWT Token Management**: Generate and validate access and refresh tokens - **Middleware Support**: Ready-to-use Echo middleware for authentication and authorization - **Role-Based Access Control**: Built-in role validation middleware - **Company Scoping**: Company-level access control middleware - **Token Blacklisting**: Support for token invalidation (Redis-ready) - **Injectable Configuration**: Dependency injection for flexible configuration management - **Configuration Providers**: Multiple ways to create configurations (environment, custom, hybrid) - **Security Best Practices**: Secure token generation and validation ## Quick Start ### 1. Basic Usage ```go package main import ( "tm/pkg/authorization" "tm/pkg/logger" ) func main() { // Create logger logger := logger.NewLogger() // Create configuration provider (environment-based) configProvider := authorization.NewEnvConfigProvider() config := configProvider.CreateConfig() // Create authorization service authService := authorization.NewAuthorizationService(config, logger) // Generate tokens tokenPair, err := authService.GenerateTokenPair( "user123", "user@example.com", "admin", "company456", ) if err != nil { log.Fatal(err) } // Validate tokens result, err := authService.ValidateAccessToken(tokenPair.AccessToken) if err != nil { log.Fatal(err) } if result.Valid { fmt.Printf("User ID: %s, Role: %s\n", result.Claims.UserID, result.Claims.Role) } } ``` ### 2. Using with Echo Framework ```go package main import ( "github.com/labstack/echo/v4" "tm/pkg/authorization" "tm/pkg/logger" ) func main() { e := echo.New() // Setup authorization logger := logger.NewLogger() configProvider := authorization.NewEnvConfigProvider() config := configProvider.CreateConfig() authService := authorization.NewAuthorizationService(config, logger) // Public routes e.POST("/login", loginHandler) // Protected routes protected := e.Group("/api") protected.Use(authorization.AuthMiddleware(authService)) { protected.GET("/profile", getProfileHandler) protected.PUT("/profile", updateProfileHandler) } // Admin routes admin := protected.Group("/admin") admin.Use(authorization.AdminMiddleware(authService)) { admin.POST("/users", createUserHandler) admin.GET("/users", listUsersHandler) } // Company-scoped routes company := protected.Group("/company/:company_id") company.Use(authorization.CompanyMiddleware(authService)) { company.GET("/tenders", getCompanyTendersHandler) } e.Start(":8080") } ``` ### 3. Configuration Management The authorization package uses dependency injection for configuration. You can create configurations using different providers: #### Configuration Providers The package provides several configuration providers that implement the `ConfigProvider` interface: ```go type ConfigProvider interface { CreateConfig() *AuthorizationConfig } ``` #### Environment-based Configuration ```go // Create configuration from environment variables configProvider := authorization.NewEnvConfigProvider() config := configProvider.CreateConfig() ``` #### Custom Configuration ```go // Create custom configuration customConfig := &authorization.AuthorizationConfig{ AccessTokenSecret: "my-secret-key", RefreshTokenSecret: "my-refresh-secret", AccessTokenExpiry: 30 * time.Minute, RefreshTokenExpiry: 14 * 24 * time.Hour, Issuer: "my-app", Audience: "my-api", } configProvider := authorization.NewCustomConfigProvider(customConfig) config := configProvider.CreateConfig() ``` #### Hybrid Configuration ```go // Combine multiple configuration sources with priority envProvider := authorization.NewEnvConfigProvider() customProvider := authorization.NewCustomConfigProvider(customConfig) hybridProvider := authorization.NewHybridConfigProvider(envProvider, customProvider) config := hybridProvider.CreateConfig() // The hybrid provider applies configurations in order: // 1. Environment variables (base) // 2. Custom overrides (priority) ``` #### File-based Configuration (Future) ```go // File-based configuration (placeholder for future implementation) fileProvider := authorization.NewFileConfigProvider("config.yaml") config := fileProvider.CreateConfig() ``` #### Environment Variables ```bash # Required export TM_ACCESS_TOKEN_SECRET="your-super-secret-access-key-here" export TM_REFRESH_TOKEN_SECRET="your-super-secret-refresh-key-here" # Optional (with defaults) export TM_ACCESS_TOKEN_EXPIRY="15m" export TM_REFRESH_TOKEN_EXPIRY="168h" # 7 days export TM_JWT_ISSUER="tender-management" export TM_JWT_AUDIENCE="tender-management-api" ``` ## API Reference ### AuthorizationService Interface ```go type AuthorizationService interface { // Generate tokens GenerateTokenPair(userID, email, role, companyID string) (*TokenPair, error) GenerateAccessToken(userID, email, role, companyID string) (string, error) GenerateRefreshToken(userID, email, role, companyID string) (string, error) // Validate tokens ValidateToken(tokenString string) (*TokenValidationResult, error) ValidateAccessToken(tokenString string) (*TokenValidationResult, error) ValidateRefreshToken(tokenString string) (*TokenValidationResult, error) // Token management RefreshAccessToken(refreshToken string) (string, error) InvalidateToken(tokenString string) error IsTokenBlacklisted(tokenString string) (bool, error) } ``` ### Middleware Functions ```go // Authentication middleware AuthMiddleware(authService AuthorizationService) echo.MiddlewareFunc // Role-based access control RoleMiddleware(authService AuthorizationService, requiredRoles ...string) echo.MiddlewareFunc // Admin-only access AdminMiddleware(authService AuthorizationService) echo.MiddlewareFunc // Company-scoped access CompanyMiddleware(authService AuthorizationService) echo.MiddlewareFunc // Optional authentication OptionalAuthMiddleware(authService AuthorizationService) echo.MiddlewareFunc ``` ### Context Helpers ```go // Extract user information from context userID, email, role, companyID, authenticated := GetUserFromContext(c) // Extract token claims claims := GetTokenClaimsFromContext(c) // Check authentication status if IsAuthenticated(c) { // User is authenticated } ``` ## Token Structure ### Access Token Claims ```json { "user_id": "uuid-string", "email": "user@example.com", "role": "admin", "company_id": "company-uuid", "token_type": "access", "iss": "tender-management", "sub": "uuid-string", "aud": ["tender-management-api"], "exp": 1640995200, "nbf": 1640994300, "iat": 1640994300 } ``` ### Refresh Token Claims ```json { "user_id": "uuid-string", "email": "user@example.com", "role": "admin", "company_id": "company-uuid", "token_type": "refresh", "iss": "tender-management", "sub": "uuid-string", "aud": ["tender-management-api"], "exp": 1641600000, "nbf": 1640994300, "iat": 1640994300 } ``` ## Security Features ### Token Security - **Separate Secrets**: Access and refresh tokens use different signing secrets - **Short Expiry**: Access tokens expire quickly (default: 15 minutes) - **Long Expiry**: Refresh tokens last longer (default: 7 days) - **Type Validation**: Tokens are validated against their intended type - **Blacklist Support**: Tokens can be invalidated and blacklisted ### Best Practices - **Environment Variables**: Never hardcode secrets in code - **Strong Secrets**: Use cryptographically strong random secrets - **HTTPS Only**: Always use HTTPS in production - **Token Rotation**: Implement refresh token rotation for security - **Audit Logging**: Log all authentication and authorization events ## Configuration Validation The package automatically validates configuration on startup: ```go config := authorization.LoadConfigFromEnv() if err := config.ValidateConfig(); err != nil { log.Fatal("Invalid authorization configuration:", err) } ``` Validation checks: - Non-empty secrets - Valid expiry durations - Access token expiry < refresh token expiry - Non-empty issuer and audience ## Error Handling All functions return descriptive errors: ```go result, err := authService.ValidateAccessToken(token) if err != nil { // Handle validation error return err } if !result.Valid { if result.Expired { return response.Unauthorized(c, "Token has expired") } return response.Unauthorized(c, result.Error) } ``` ## Future Enhancements - **Redis Integration**: Full token blacklist implementation - **Rate Limiting**: Token generation rate limiting - **Audit Trail**: Comprehensive authentication audit logging - **Multi-Tenant**: Enhanced company-level security - **OAuth2 Support**: Integration with external OAuth providers ## Dependencies - `github.com/golang-jwt/jwt/v5` - JWT implementation - `github.com/labstack/echo/v4` - HTTP framework - `tm/pkg/logger` - Internal logging package - `tm/pkg/response` - Internal response package ## License This package is part of the Tender Management system and follows the same license terms.