cors

A spec-compliant, configurable CORS middleware for Go's net/http, with drop-in compatibility for most Go web frameworks.

Library
Go
vv1.11.1
2,895 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
55 /100 Fair
Development Activity 52
Maintenance 4
Community 64
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
77 /100 Good
Architecture 80
Code Quality 85
Innovation 78
Learning Curve 65

rs/cors is a net/http handler implementing the W3C Cross-Origin Resource Sharing specification for Go HTTP servers. It wraps an existing http.Handler and takes care of preflight (OPTIONS) requests and actual-request headers — origin matching (exact, wildcard, or a custom validator function), allowed methods and headers, exposed headers, credentialed requests, private-network access, and preflight cache duration — all driven from a single Options struct passed to cors.New.

Beyond the standard net/http Handler wrapper, the package exposes HandlerFunc and ServeHTTP variants so it plugs directly into Martini- and Negroni-style middleware chains, and the repo ships worked examples for a dozen popular routers and frameworks (Chi, Gorilla, Gin, HttpRouter, Goji, Buffalo, Alice, and more). A cors.Default() constructor gives sane defaults for quick starts, and cors.AllowAll() provides a permissive preset for local development or fully public APIs.

The library has also been hardened against a specific security foot-gun: earlier versions would reflect the request Origin back when AllowedOrigins was * and AllowCredentials was true, silently defeating a protection the CORS spec relies on. That behavior was removed; achieving it now requires an explicit AllowOriginFunc opt-in, with the security tradeoff documented directly in the README.

What You Get

  • A net/http-native Cors handler built via cors.New(Options{...}) that wraps any http.Handler
  • Flexible origin matching: exact allowlist, wildcard patterns (https://*.example.com), or a custom AllowOriginFunc/AllowOriginVaryRequestFunc for per-request logic
  • Automatic preflight (OPTIONS) handling — allowed methods, allowed headers (validated against a sorted-set implementation of the Fetch spec’s CORS-safelist rules), Access-Control-Max-Age caching, and correct Vary header emission
  • Support for credentialed requests (AllowCredentials) and Private Network Access (AllowPrivateNetwork) with the guardrails needed to avoid the wildcard-plus-credentials misconfiguration
  • Compatibility shims (Handler, HandlerFunc, ServeHTTP) so it drops into net/http, Martini, and Negroni-style middleware chains, plus a dedicated Gin wrapper package

Common Use Cases

  • Enabling a Go backend API to be called from a separate frontend origin (e.g. a React/Vue app on a different port or domain) during local development and in production
  • Locking down a public API to a specific set of partner origins while still supporting browser preflight requests correctly
  • Allowing credentialed (cookie-based) cross-origin requests from a known set of subdomains via wildcard origin patterns
  • Building an internal tool or admin API that needs Private Network Access headers to be reachable from a public site running on a user’s LAN
  • Adding CORS support to a Go server built on Gin, Chi, Gorilla, or another router without writing custom middleware

Under The Hood

Architecture

The library is a small, single-purpose net/http middleware: cors.New(Options) builds a Cors struct that precomputes as much as possible at construction time (normalized origin lists, a SortedSet of allowed headers, joined exposed-header and max-age strings) so that the hot path in handlePreflight/handleActualRequest does minimal work per request. Framework compatibility is handled by exposing three call shapes — Handler(http.Handler) http.Handler, HandlerFunc(w, r), and ServeHTTP(w, r, next) — rather than depending on any specific router’s middleware interface, and a separate wrapper/gin package adapts the core handler to Gin’s gin.HandlerFunc signature without pulling Gin into the main module’s dependency graph. An internal package houses SortedSet, a small data structure (adapted from jub0bs/cors) that validates the Access-Control-Request-Headers preflight header against RFC 9110’s list-syntax rules without allocating per request.

Tech Stack

The module is dependency-free — it targets Go 1.23 and uses only the standard library (net/http, slices, strconv, strings, log, os), which keeps it safe to add to any Go service without dependency-graph concerns. The examples/ and wrapper/ directories are separate Go modules with their own go.mod/go.sum, so framework-specific dependencies (Gin, Gorilla, Chi, etc.) never leak into the core library’s build.

Code Quality

The core package carries an extensive test suite (cors_test.go at over 800 lines, plus dedicated tests for the wildcard matcher and the internal SortedSet) covering preflight edge cases, wildcard origins, credentialed requests, and private-network headers, alongside a benchmark suite tracking allocation counts for the hot paths. CI runs go test ./... on every push and publishes a coverage report/chart. Naming and error handling follow idiomatic Go conventions (explicit boolean returns, no panics in request handling); there is no linter config checked in, so style enforcement relies on go vet/CI conventions rather than an explicit linter.

What Makes It Unique

Rather than trying to own routing or become a framework, the library is deliberately scoped to just CORS semantics and ships explicit documentation of a real security incident (issues #55/#57, the wildcard-plus-credentials origin-reflection behavior) and how it was resolved — a level of transparency about security tradeoffs that’s uncommon in middleware READMEs. The internal.SortedSet header validator, adapted from a more spec-rigorous sibling project, is a notably careful implementation of the Fetch standard’s list-based header value parsing rather than a naive string split.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers