last modified April 11, 2024
In this article we define CORS and show how to work with CORS in Golang.
Browsers enforce the same-origin policy which permits JS scripts in a web page to access data in other web pages only if both web pages have the same origin. An origin is defined as a combination of URL scheme, host name, and port number. The policy helps isolate potentially malicious documents, reducing possible attack vectors.
Cross-Origin Resource Sharing (CORS) is an HTTP-header based process that defines which origins from which a browser is permitted to load resources.
CORS relaxes the same-origin policy via the usage of HTTP CORS headers.
Request headers:
- Origin - indicates the server the origin of the request
- Access-Control-Request-Method - indicates the server which HTTP methods the request implements
- Access-Control-Request-Headers - indicates the server which headers the request includes
Response headers:
- Access-Control-Allow-Origin - the origins that the server allows
- Access-Control-Allow-Methods - comma-separated list of methods that the server allows
- Access-Control-Allow-Headers - a comma-separated list of headers that the server allows
- Access-Control-Expose-Headers - a comma-separated list of headers that clients are allowed to access from a response
- Access-Control-Max-Age - tells the browser how long (in seconds) to cache the response to the preflight request
- Access-Control-Allow-Credentials
In the following example, we enable CORS in a Go server application.
index.html
<!DOCTYPE html> <html lang=“en”>
<head> <meta charset=“UTF-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1.0”> <title>Home</title> </head>
<body>
<script>
async function doRequest() {
let url = 'http://localhost:8080/hello';
let res = await fetch(url);
if (res.ok) {
let text = await res.text();
return text;
} else {
return `HTTP error: ${res.status}`;
}
}
doRequest().then(data => {
document.getElementById("output").innerText = data;
});
</script>
<div id="output">
</div>
</body>
</html>
In the HTML web page, we use the JS Fetch API to create a GET request. The script reads the response and sets it into the output div element. To try the example, load this webpage via a web server such as nginx or use a liveserver VS Code extension.
main.go
package main
import ( “fmt” “log” “net/http” )
func main() {
http.HandleFunc("/hello", HelloHandler)
log.Println("Listening...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func HelloHandler(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5501")
w.Header().Set("Access-Control-Max-Age", "15")
fmt.Fprintf(w, "Hello, there!")
}
Inside the HelloHandler, we set the CORS policy for our server.
log.Fatal(http.ListenAndServe(":8080", nil))
The application runs on localhost on port 8080. To access resources of this server from other origins, in is necessary to enable them.
w.Header().Set(“Content-Type”, “text/plain; charset=utf-8”) w.Header().Set(“Access-Control-Allow-Origin”, “http://127.0.0.1:5501”) w.Header().Set(“Access-Control-Max-Age”, “15”)
We enable set the CORS policy for this server. JS scripts from http://127.0.0.1:5501 origin can access our resources.
The github.com/rs/cors is a third-party package which defines net/http handler implementing Cross Origin Resource Sharing W3 specification in Golang.
main.go
package main
import ( “fmt” “net/http”
"github.com/rs/cors"
)
func main() {
mux := http.NewServeMux()
cors := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{
http.MethodPost,
http.MethodGet,
},
AllowedHeaders: []string{"*"},
AllowCredentials: false,
})
mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprintln(w, "Hello there!")
})
handler := cors.Handler(mux)
http.ListenAndServe(":8080", handler)
}
In the example, we use the github.com/rs/cors to implement the CORS policy for our server. We enable two methods: GET and POST. With *, we allow all origins.
Go web frameworks, such as Echo, Gin, or Fiber have ready-to-use middlewares which enable CORS policies.
main.go
package main
import ( “net/http”
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
var ( words = []string{“kind”, “warm”, “cup”, “coin”, “blue”} )
func getWords(c echo.Context) error { return c.JSON(http.StatusOK, words) }
func main() {
e := echo.New()
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete},
}))
e.GET("/api/words", getWords)
e.Logger.Fatal(e.Start(":8080"))
}
The example uses a CORS middleware in an Echo framework.
In this article we have worked with CORS in Go.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Go tutorials.