ZetCode

Go CORS

last modified September 26, 2022

In this article, we define CORS and show how to work with CORS in Golang.

$ go version
go version go1.18.1 linux/amd64

We use Go version 1.18.

Same-origin policy

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.

CORS

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:

Response headers:

Go CORS simple example

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.

Go CORS handler

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.

Echo CORS example

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 tutorial, we have worked with CORS in Go.

List all Go tutorials.