Home > Blockchain >  multiple CORS values being rejected in Go gin api
multiple CORS values being rejected in Go gin api

Time:02-11

In my Go API, I'm using gin, and I have one value set in my Access-Control-Allow-Origin header. If I have more than one, my react UI throws an error to the effect of The Access-Control-Allow-Origin header contains multiple values 'http://value1, http://value2', but only one is allowed.... I need to set multiple values. How do I do this?

The API is a reverse proxy, and here's the relevant code:

func proxy(c *gin.Context) {
  var remote = "myUrl"
  proxy := httputil.NewSingleHostReverseProxy(remote)
  proxy.Director = func(req *http.Request) {
        req.Header.Set("Authorization", "My Auth Values")
        req.Host = remote.Host
        req.URL.Scheme = remote.Scheme
        req.URL.Host = remote.Host
    }
    proxy.ModifyResponse = addCustomHeader
    proxy.ServeHTTP(c.Writer, c.Request)
}

func addCustomHeader(r *http.Response) error {
    r.Header["Access-Control-Allow-Origin"] = []string{"value1"}
    return nil
}

CodePudding user response:

You only need a single value for each incoming request. The usual technique is to configure trusted origins on the server, eg:

  • trustedOrigins: [https://www.domain1.com, https://www.domain2.com]

Then check the runtime value of the origin header, which is sent by all modern browsers. If this is a trusted origin then add CORS headers:

A wildcard could be used but that is not recommended and also will not work as intended if you are also using credentialed requests (eg those with cookies).

CodePudding user response:

A CORS header can only contain a single value. If you want to implement your own CORS middleware, you need to work around that fact.

A simple CORS middleware will add the Access-Control-Allow-Origin header with the value of the specific address of the incoming request, usually taken from the Referer or Origin header. Typically, you match this against a list or map first, to see if it's in your allow list. If so, then the address of the request is added as allowed origin (as a single value).

A simple example could look like this

allowList := map[string]bool{
    "https://www.google.com": true,
    "https://www.yahoo.com":  true,
}

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    if origin := r.Header.Get("Origin"); allowList[origin] {
        w.Header().Set("Access-Control-Allow-Origin", origin)
    }
})

Since you are using the reverse proxy, you can access the request from the response.

mod := func(allowList map[string]bool) func(r *http.Response) error {
    return func(r *http.Response) error {
        if origin := r.Request.Header.Get("Origin"); allowList[origin] {
            r.Header.Set("Access-Control-Allow-Origin", origin)
        }
        return nil
    }
}

proxy := &httputil.ReverseProxy{
    Director: func(r *http.Request) {
        r.URL.Scheme = "https"
        r.URL.Host = "go.dev"
        r.Host = r.URL.Host
    },
    ModifyResponse: mod(allowList),
}
  • Related