composed5/pkg/middleware/cors.go
jordan e57cfe1f57
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/manual/woodpecker Pipeline was successful
Initialize project from skeleton template
2026-02-01 19:58:14 +00:00

99 lines
3.5 KiB
Go

// 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
}