2

I have a golang HTTP server with code like:

    http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
    log.Println("New incoming request")

    // Authenticate
    if u, p, ok := r.BasicAuth(); ok {
      log.Println("Success")
      return
    }
    log.Println("Failed")

I call this HTTP endpoint from a JS frontend, a react app deployed on port 3000, using code:

      fetch('http://localhost:8080/login', {
            method: 'post',
            headers: {
                'Authorization': 'Basic ' + btoa(authHeader),
                'Content-Type': 'application/x-www-form-urlencoded',
                'Access-Control-Allow-Origin': '*'
            },
                body: 'A=1&B=2'
            })
            .then(function (response) {
                console.log("Authentication Success")
            })
            .catch(function (err) {
                console.log("Authentication fail", err)
            });

The above code fails with the following logs.

On the server side:

New incoming request
Failed

On the browser, in the developer tools logs:

Fetch API cannot load http://localhost:8080/login. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Can someone help fix the authentication problem ? I am not sure if I am missing something related to CORS on the server side or doing bad authentication on the client side. Any help ? Thanks.

Sankar
  • 6,192
  • 12
  • 65
  • 89
  • show the go setup for the cors please. –  Nov 08 '16 at 11:12
  • `Access-Control-Allow-Origin` is not a request header it should be on the server response. read https://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Simple_example – Nima Ghotbi Nov 08 '16 at 11:25
  • `Fetch API cannot load http://localhost:8080/login. Response for preflight has invalid HTTP status code 401` is the error message that I get if I add `w.Header().Set("Access-Control-Allow-Origin", "*")` in the server HTTP handler. As of now the server code does not have any CORS related code and I am looking for that exactly. – Sankar Nov 08 '16 at 12:16

2 Answers2

4

The Access-Control-Allow-Origin: * has to be sent from the server, not by the client. Assuming you are in a standard net/http handler function, try this code:

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    if (r.Method == "OPTIONS") {
        w.Header().Set("Access-Control-Allow-Headers", "Authorization") // You can add more headers here if needed
    } else {
        // Your code goes here
    }
}
PiMaker
  • 511
  • 3
  • 16
  • I have tried this earlier and it did not work. I get: `Fetch API cannot load http://localhost:8080/login. Response for preflight has invalid HTTP status code 401 ` in the chrome. `ok` still remains false in the server side. – Sankar Nov 08 '16 at 12:15
  • What you're looking at is an error message from the CORS Preflight check. See http://stackoverflow.com/questions/22972066/how-to-handle-preflight-cors-requests-on-a-go-server on how to implement that in Go. – PiMaker Nov 08 '16 at 12:20
  • I get only one `New incoming request` on the server side logs, for each request from the browser. Not two requests (one r.POST and another r.OPTIONS) are coming as per the server side logs. – Sankar Nov 08 '16 at 12:59
  • Yes, you get the OPTIONS request after which the browser aborts. If you implement the preflight correctly, the browser will continue to send the actual fetch request. – PiMaker Nov 08 '16 at 13:00
  • Can you update your code to include OPTIONS handling ? Whatever I have tried seem to not fix the issue. All the code that my server currently has is in the question. – Sankar Nov 08 '16 at 13:34
  • I have updated the answer although you might have to specify your methods/headers explicitly instead of * – PiMaker Nov 08 '16 at 13:51
  • The * was the culprit. Chrome seem to block that for some reason. The server code should return: `w.Header().Set("Access-Control-Allow-Headers", "Authorization")` This is all that is needed. Can you update the code ? I will accept it. – Sankar Nov 09 '16 at 18:01
  • Like this? Also, glad to help – PiMaker Nov 09 '16 at 18:05
0

First - you need to use schema in your handler:

w.Header().Set("Access-Control-Allow-Origin", "*")
    if (r.Method == "OPTIONS") {
        w.Header().Set("Access-Control-Allow-Headers", "Authorization") // You can add more headers here if needed
    } else {
        // Your code goes here
    }

But before it you need to specify in main "OPTIONS":

router.HandleFunc("/your_route/", your_method).Methods("POST", "OPTIONS")

It's because your browser doing 2 request - first to check ability to use some headers (Authorization for example) and next step is posting data

Jsperk
  • 124
  • 1
  • 11
Reviashko
  • 11
  • 1