Skip to content

jub0bs/cors

Repository files navigation

jub0bs/cors

Go Reference license build codecov goreport

A principled CORS middleware library for Go, designed to be both easier to use and harder to misuse than existing alternatives.

About CORS

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 package allows you to configure and build net/http middleware that implement CORS.

Installation

go get github.com/jub0bs/cors

jub0bs/cors requires Go 1.23 or above.

Example

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 or POST, and
  • (optionally) with request header Authorization,

and how to apply the middleware in question to all the resources accessible under some /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

  log.Fatal(http.ListenAndServe(":8080", mux))
}

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.

A note about testing

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.

Documentation

The documentation is available on pkg.go.dev.

Moreover, guidance on how to use jub0bs/cors with popular third-party routers can be found in jub0bs/cors-examples.

Code coverage

coverage

Benchmarks

Some benchmarks pitting jub0bs/cors against rs/cors are available in jub0bs/cors-benchmarks.

License

All source code is covered by the MIT License.

Additional resources

Reasons for favoring rs/cors over jub0bs/cors

Despite all of jub0bs/cors's goodness, you may still have valid reasons for sticking with rs/cors, at least for the time being. Here is as exhaustive a list as I could come up with: