A principled CORS middleware library for Go, designed to be both easier to use and harder to misuse than existing alternatives.
The Same-Origin Policy (SOP) is a security mechanism that Web browsers implement to protect their users. In particular, the SOP places some restrictions on cross-origin network access, in terms of both sending and reading.
Cross-Origin Resource Sharing (CORS) is a protocol that lets servers instruct browsers to relax those restrictions for select clients.
This library allows you to configure and build net/http middleware that implement CORS. It distinguishes itself from other CORS middleware libraries by providing the following features:
- a simple and coherent API;
- thorough documentation;
- extensive configuration validation;
- programmatic handling of configuration errors;
- safe-by-default middleware behavior;
- a useful debug mode;
- on-the-fly, concurrency-safe middleware reconfigurability;
- strong performance guarantees;
- support for Private-Network Access;
- full compliance with the Fetch standard.
Despite all of this library's goodness, you may still have valid reasons for favoring libraries like the more popular rs/cors. Here is as exhaustive a list as I could come up with:
- You need more flexibility than that afforded by the origin patterns supported by this library; but do bear in mind that excessive flexibility in this regard implies security risks.
- You want to log a message for every single request processed by your CORS middleware; but do you, really?
go get github.com/jub0bs/cors
This library requires Go 1.23 or above.
The following program demonstrates how to create a CORS middleware that
- allows anonymous access from Web origin
https://example.com
, - with requests whose method is either
GET
orPOST
(orHEAD
), and - (optionally) with request header
Authorization
,
and how to apply the middleware in question to all the resources accessible
under the /api/
path:
package main
import (
"io"
"log"
"net/http"
"github.com/jub0bs/cors"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /hello", handleHello) // note: not configured for CORS
// create CORS middleware
corsMw, err := cors.NewMiddleware(cors.Config{
Origins: []string{"https://example.com"},
Methods: []string{http.MethodGet, http.MethodPost},
RequestHeaders: []string{"Authorization"},
})
if err != nil {
log.Fatal(err)
}
corsMw.SetDebug(true) // turn debug mode on (optional)
api := http.NewServeMux()
api.HandleFunc("GET /users", handleUsersGet)
api.HandleFunc("POST /users", handleUsersPost)
mux.Handle("/api/", http.StripPrefix("/api", corsMw.Wrap(api))) // note: method-less pattern here
if err := http.ListenAndServe(":8080", mux); err != http.ErrServerClosed {
log.Fatal(err)
}
}
func handleHello(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hello, World!")
}
func handleUsersGet(_ http.ResponseWriter, _ *http.Request) {
// omitted
}
func handleUsersPost(_ http.ResponseWriter, _ *http.Request) {
// omitted
}
Try it out yourself by saving this program to a file named server.go
.
You may need to adjust the port number if port 8080 happens to be unavailable
on your machine. Then build and run your server:
go build server.go
./server
If no error occurred, the server is now running on localhost:8080
and
the various resources accessible under the /api/
path are now configured
for CORS as desired.
If you need to handle CORS-configuration errors programmatically, see package cfgerrors.
Be aware that, for performance reasons, CORS middleware produced by this
library closely adheres to guarantees (provided by the Fetch standard)
about the format of some CORS headers. In particular, if you wish to write
tests that exercise CORS middleware via CORS-preflight requests that include an
Access-Control-Request-Headers
header, keep in mind that you should
specify the comma-separated elements in that header value
- in lower case,
- in lexicographical order,
- without repetitions.
Otherwise, the CORS middleware will cause preflight to fail.
The documentation is available on pkg.go.dev.
Moreover, guidance on how to use this library with popular third-party routers can be found in jub0bs/cors-examples.
Some benchmarks pitting this library against rs/cors are available in jub0bs/cors-benchmarks.
All source code is covered by the MIT License.
- Fearless CORS: a design philosophy for CORS middleware libraries (and a Go implementation) (blog post)
- jub0bs/cors: a better CORS middleware library for Go (blog post)
- Reconfigurable CORS middleware with jub0bs/cors (blog post)
- Useful Functional-Options Tricks for Better Libraries (GopherCon Europe 2023) (video)
- github.com/jub0bs/fcors (this library's predecessor)