// Package middleware provides HTTP middleware for services. package middleware import ( "net/http" "github.com/go-chi/cors" ) // CORSConfig configures CORS behavior for HTTP services. // Used to control cross-origin requests from browsers. type CORSConfig struct { // AllowedOrigins lists domains allowed to make cross-origin requests. // Use []string{"*"} for open access (dev/staging), specific domains for production. // Example: []string{"https://app.example.com", "https://admin.example.com"} AllowedOrigins []string // AllowedMethods lists HTTP methods that can be used in cross-origin requests. // Example: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"} AllowedMethods []string // AllowedHeaders lists request headers that can be included in cross-origin requests. // Must include headers used by services (Authorization, X-Request-ID, etc.) AllowedHeaders []string // ExposedHeaders lists response headers that the browser can expose to JavaScript. // Useful for pagination headers, custom metadata, etc. ExposedHeaders []string // AllowCredentials controls whether browsers can send credentials (cookies, auth headers) // in cross-origin requests. MUST be false when AllowedOrigins is "*". AllowCredentials bool // MaxAge specifies how long (in seconds) browsers can cache preflight responses. // Reduces OPTIONS requests for the same resource. MaxAge int } // DefaultCORSConfig returns sensible defaults for services. // Designed for local development and staging environments. // // Defaults: // - AllowedOrigins: ["*"] (override in production to specific domains) // - AllowedMethods: GET, POST, PUT, PATCH, DELETE, OPTIONS // - AllowedHeaders: ["*"] (allows any header - simplest for development) // - ExposedHeaders: Link (for pagination) // - AllowCredentials: false (required when AllowedOrigins is "*") // - MaxAge: 300 seconds (5 minutes) // // Production services should override AllowedOrigins with specific domains, // set AllowCredentials: true if needed, and optionally restrict AllowedHeaders. func DefaultCORSConfig() CORSConfig { return CORSConfig{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"*"}, ExposedHeaders: []string{"Link"}, AllowCredentials: false, MaxAge: 300, } } // CORS returns middleware that handles CORS headers for cross-origin requests. // Uses github.com/go-chi/cors under the hood for RFC compliance. // // The middleware: // - Handles preflight OPTIONS requests automatically // - Sets Access-Control-* headers on actual requests // - Validates origins against AllowedOrigins // - Caches preflight responses according to MaxAge // // Usage: // // r := chi.NewRouter() // r.Use(middleware.CORS(middleware.DefaultCORSConfig())) // // Production example: // // cfg := middleware.CORSConfig{ // AllowedOrigins: []string{"https://app.example.com"}, // AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"}, // AllowedHeaders: []string{"Content-Type", "Authorization"}, // AllowCredentials: true, // MaxAge: 600, // } // r.Use(middleware.CORS(cfg)) func CORS(cfg CORSConfig) func(http.Handler) http.Handler { c := cors.New(cors.Options{ AllowedOrigins: cfg.AllowedOrigins, AllowedMethods: cfg.AllowedMethods, AllowedHeaders: cfg.AllowedHeaders, ExposedHeaders: cfg.ExposedHeaders, AllowCredentials: cfg.AllowCredentials, MaxAge: cfg.MaxAge, }) return c.Handler }