package middleware import "net/http" // CorsMiddleware — browser CORS for Harbor Desk FE. // Note: cannot combine Access-Control-Allow-Origin: * with Allow-Credentials: true // (browsers reject). FE uses Bearer token (no cookies), so no credentials header. type CorsMiddleware struct{} func NewCorsMiddleware() *CorsMiddleware { return &CorsMiddleware{} } func (m *CorsMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { setHeader(w, r) if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } next(w, r) } } func (m *CorsMiddleware) Handler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { setHeader(w, r) if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } w.WriteHeader(http.StatusNotFound) }) } func setHeader(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") if origin == "" { origin = "*" } // Echo request origin (dev-friendly). Production can whitelist later. w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Vary", "Origin") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Request-Id, device_id") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH") w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Type") // Do NOT set Allow-Credentials with wildcard; FE uses Authorization header only. }