golang preflight request error - go

I have set up my Go backend using gorilla/mux and rs/cors. When I try to send a request including a custom header (Bearer) it fails.
My server setup looks like this:
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/users", GetUsers).Methods("GET")
router.HandleFunc("/", GetUsers).Methods("GET")
router.HandleFunc("/tweets", GetTweets).Methods("GET")
router.HandleFunc("/login", Login).Methods("POST")
router.HandleFunc("/profile/tweets", ProfileTweets).Methods("GET")
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PATCH"},
AllowedHeaders: []string{"Bearer", "Content_Type"},})
handler := c.Handler(router)
log.Fatal(http.ListenAndServe(":8080", handler))
I have tried various other solutions (such as adding OPTIONS in the Methods call.
The endpoint for which I am trying to pass the Bearer token is the /profile/tweets endpoint.
I'm unsure how to continue with gorilla/mux and rs/cors in terms of adding the preflight request.
The actual error that I get:
Fetch API cannot load http://localhost:8080/profile/tweets. 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:4200' is therefore not allowed
access. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled.
Thanks!

I've just solved the problem. I had a typo in the AllowedHeaders as pointed out by #Francois P.
In addition, I had to add OptionsPassthrough and the OPTIONS method, like so:
router.HandleFunc("/profile/tweets", ProfileTweets).Methods("GET","OPTIONS")
c := cors.New(cors.Options{
AllowedMethods: []string{"GET","POST", "OPTIONS"},
AllowedOrigins: []string{"*"},
AllowCredentials: true,
AllowedHeaders: []string{"Content-Type","Bearer","Bearer ","content-type","Origin","Accept"},
OptionsPassthrough: true,
})

Related

Go Mux CORS error with both gorilla/handlers and rs/cors [duplicate]

I have fairly simple setup here as described in the code below. But I am not able to get the CORS to work. I keep getting this error:
XMLHttpRequest cannot load http://localhost:3000/signup. 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:8000' is therefore not allowed access. The
response had HTTP status code 403.
I am sure I am missing something simple here.
Here is the code I have:
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
log.Fatal(http.ListenAndServe(":3000", handlers.CORS()(router)))
}
Please read the link Markus suggested, and also about what triggers CORS pre-flight requests.
Pre-flight requests: You may have a content type like JSON, or some other custom header that's triggering a pre-flight request, which your server may not be handling. Try adding this one, if you're using the ever-common AJAX in your front-end: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With
Gorilla's handlers.CORS() will set sane defaults to get the basics of CORS working for you; however, you can (and maybe should) take control in a more functional manner.
Here's some starter code:
// Where ORIGIN_ALLOWED is like `scheme://dns[:port]`, or `*` (insecure)
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{os.Getenv("ORIGIN_ALLOWED")})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
// start server listen
// with error handling
log.Fatal(http.ListenAndServe(":" + os.Getenv("PORT"), handlers.CORS(originsOk, headersOk, methodsOk)(router)))
You can get more details here: Why doesn’t Postman get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when my JavaScript code does? about this issue.
Also try this handler: Go Cors Handler which should solve your issue. I find this much cleaner and easy to resolve the issue.
package main
import (
"log"
"net/http"
"github.com/rs/cors"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8000"},
AllowCredentials: true,
})
handler := c.Handler(router)
log.Fatal(http.ListenAndServe(":3000", handler)
}
You should create a CORSOption object. For example to allow any origin, Use this code:
corsObj:=handlers.AllowedOrigins([]string{"*"})
Then you pass this object to your handle.CORS function:
log.Fatal(http.ListenAndServe(":3000", handlers.CORS(corsObj)(router)))
For testing it you can use CURL:
curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://127.0.0.1:3000
When it works you should see those headers:
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
Final code is here: https://play.golang.org/p/AOrlJsWhvf
More info:
AllowedOrigin function
How can you debug a CORS request with cURL?
I realize this is an old issue but nonetheless it took me 30min to get this right.
handler = handlers.CORS(
// handlers.AllowedMethods([]string{"GET", "POST", "PUT"}),
handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"}),
// handlers.AllowedOrigins([]string{"*"}),
)(handler)
Things to note:
AllowedMethods does NOT need to explicitly include OPTIONS, this is part of the CORS handler
AllowedHeaders need to be explicitly mentioned, * is not a valid wildcard. Typical ajax libraries will send Content-Type when requesting something like application/json, so add that as well.
* is the default for AllowedOrigin
After declaring the mux object, add the accessControlMiddleware as a middleware to the declared object.
func main(){
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.Use(accessControlMiddleware)
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
// access control and CORS middleware
func accessControlMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS,PUT")
w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")
if r.Method == "OPTIONS" {
return
}
next.ServeHTTP(w, r)
})
}
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
"github.com/rs/cors"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
//cors optionsGoes Below
corsOpts := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8100"}, //you service is available and allowed for this base url
AllowedMethods: []string{
http.MethodGet,//http methods for your app
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodOptions,
http.MethodHead,
},
AllowedHeaders: []string{
"*",//or you can your header key values which you are using in your application
},
})
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
Base on jeremiah.trein's answer.
CORS filters are set on server side. Request may work with Postman and fail with a browser because Postman doesn't send preflight request whereas a browser does.
Setting the CORS filters will allow you to configure the origins, methods and headers that the backend shall accept.
In addition, if your browser emits POST or PUT requests that contain a json payload (which is quite reasonnable), you'll need to add 'Content-Type' to the allowed headers.
Finally the handlers.CORS()(router) does not only work with the http.ListenAndServe function but also with http.Handle().
The snippet of code might as well look like:
router := mux.NewRouter()
// do all your routes declaration
headersOK := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOK := handlers.AllowedOrigins([]string{"*"})
methodsOK := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS", "DELETE", "PUT"})
http.Handle("/", handlers.CombinedLoggingHandler(os.Stderr, handlers.CORS(headersOK, originsOK, methodsOK)(router)))
It is worth mentionning that i have successfuly used this snippet of code in a Google Cloud Platform Standard AppEngine (and I believe it would work in a Flex AppEngine as well).
The aformentioned package github.com/rs/cors provides a constructor
AllowAll() *Cors
that
...create a new Cors handler with permissive configuration allowing all
origins with all standard methods with any header and credentials.

Disable CSRF on JSON API Calls

I have a website project. It uses Go and the Gorilla and it's CSRF packages to protect against CSRF. I also have a JSON API that authenticates using a JWT like token provider (internal), so a user must authenticate with that before issuing a JSON request each time. So the CSRF is not an issue on the JSON side. At least I don't think so.
Here's my code, where I am using a NewRouter for web Paths, and a Subrouter for the /api/v1/[endpoint]s. If I call a JSON endpoint that does a POST, the CSRF is engaged and I get a Forbidden - CSRF token invalid. I was under the assume, that perhaps a Sub Router would not have the middleware for the CSRF check associated with.
router := mux.NewRouter().StrictSlash(false)
router.Path("/").HandlerFunc(myApp.IndexHandler).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
apiRouter.Path("/dosomething").HandlerFunc(myApp.DoSomethingAPIHandler).Methods("POST", "OPTIONS")
http.ListenAndServe(":8000",
csrf.Protect(
[]byte("my-long-key-here-redacted"),
csrf.Secure(false), // Set to false as we offload SSL elsewhere
)(router)))
Question:
How do I get my API to work with or without CSRF protection? Obviously, the web paths will need to be protected to protect form posts.
One option is to only use the CSRF protection on specific HTTP handlers, rather than protecting the entire router. Note that this will require you to perform a type conversion on your myApp.IndexHandler in order to satisfy the type signature for the function returned by csrf.Protect().
router := mux.NewRouter().StrictSlash(false)
// Instead of protecting your entire router, you can protect specific HTTP
// handlers.
router.Path("/").Handler(
csrf.Protect(
[]byte("my-long-key-here-redacted"),
csrf.Secure(false),
)(http.HandlerFunc(myApp.IndexHandler)),
).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
apiRouter.Path("/dosomething").HandlerFunc(myApp.DoSomethingAPIHandler).Methods("POST", "OPTIONS")
http.ListenAndServe(
":8000",
router,
)
Alternatively, you can use the function returned from csrf.Protect() to create your own middleware, with logic to only add the CSRF protection on certain requests. You could use this approach to only add protection on endpoints with the prefix /api for example, as I've done in the code below.
protectionMiddleware := func(handler http.Handler) http.Handler {
protectionFn := csrf.Protect(
[]byte("my-long-key-here-redacted"),
csrf.Secure(false),
)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Use some kind of condition here to see if the router should use
// the CSRF protection. For the sake of this example, we'll check
// the path prefix.
if !strings.HasPrefix(r.URL.Path, "/api") {
protectionFn(handler).ServeHTTP(w, r)
return
}
handler.ServeHTTP(w, r)
})
}
router := mux.NewRouter().StrictSlash(false)
router.Path("/").HandlerFunc(myApp.IndexHandler).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
apiRouter.Path("/dosomething").HandlerFunc(myApp.DoSomethingAPIHandler).Methods("POST", "OPTIONS")
http.ListenAndServe(
":8000",
protectionMiddleware(router),
)

Negroni continues to call other handlers after request is completed

My web-application in Go (using Gorilla mux and negroni) has about 20 handlers split into three groups based on what Middleware functions should be applied. Specifically:
Group 1: Static requests (no middleware at all)
GET /favicon.ico
GET /files
GET /files/index.html
GET /files/favicon.ico
Group 2: Requests that should have CORS middleware only, no authentication:
GET /
GET /login
POST /login
GET /auth-configuration
GET /service-status
Group 3: Requests that should have both CORS and authentication middleware applied:
GET /articles
POST /articles
PUT /articles/etc
PATCH /articles/etc
This is my code that sets-up the HTTP server:
func run() {
negroniStack := setUpNegroni()
bindAddr := // ...
http.ListenAndServe(bindAddr, negroniStack)
}
func setUpNegroni() negroni.Negroni {
negroniStack := negroni.Negroni{}
staticNegroni := setUpRoutesAndMiddlewareForStaticRequests()
loginNegroni := setUpRoutesAndMiddlewareForLogin()
serviceNegroni = setUpRoutesAndMiddlewareForService()
negroniStack.UseHandler(&staticNegroni)
negroniStack.UseHandler(&loginNegroni)
negroniStack.UseHandler(&serviceNegroni)
return negroniStack
}
func setUpRoutesAndMiddlewareForStaticRequests() negroni.Negroni {
staticNegroni := negroni.Negroni{}
staticRouter := mux.NewRouter()
staticRouter.PathPrefix("/files").HandlerFunc(staticHandler)
staticRouter.Path("/favicon.ico").HandlerFunc(staticHandler)
staticNegroni.UseHandler(staticRouter)
return staticNegroni
}
func setUpRoutesAndMiddlewareForLogin() negroni.Negroni {
authNegroni := negroni.Negroni{}
corsMiddleware := cors.New(cors.Options{
AllowedMethods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"},
AllowCredentials: true,
OptionsPassthrough: false,
})
authNegroni.Use(corsMiddleware)
authRouter := mux.NewRouter()
authRouter.HandleFunc("/login", HandlePostAuth).Methods("POST")
authRouter.HandleFunc("/login", HandleGetAuth) // GET
authNegroni.UseHandler(authRouter)
return authNegroni
}
func setUpRoutesAndMiddlewareForService() negroni.Negroni {
serviceNegroni := negroni.Negroni{}
corsMiddleware := cors.New(cors.Options{
AllowedMethods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"},
AllowCredentials: true,
OptionsPassthrough: false,
})
serviceNegroni.Use(corsMiddleware)
serviceNegroni.UseFunc(jwtMiddleware)
serviceRouter := mux.NewRouter()
serviceRouter.HandleFunc("/articles", HandleGetArticles).Methods("GET")
serviceRouter.HandleFunc("/articles", HandlePostArticles).Methods("POST")
// etc
serviceNegroni.UseHandler(serviceRouter)
return serviceNegroni
}
I believe this is correct based on the "Route Specific Middleware" section in Negroni's documentation where it says:
If you have a route group of routes that need specific middleware to be executed, you can simply create a new Negroni instance and use it as your route handler.
However, when I make requests and use the debugger, I see that (*Negroni).ServeHTTP is called multiple times. For example, if I request GET /favicon.ico then the staticHandler function is called correctly and calls WriteHeader(200), but after that it then calls into the next mux.Router which calls WriteHeader(404) which prints out a warning in the terminal because the header was written twice (http: multiple response.WriteHeader calls)
If it's for a route that doesn't exist then the Gorilla default NotFoundHandler is invoked 3 times (one for each mux.Router).
How do I get Negroni to stop invoking other handlers after the request was completed?
...and if I have misconfigured my Negroni instance, why doesn't it perform checks during initialization to warn me about an invalid configuration?
My understanding is that negroni.Use and UseFunc are for setting-up middleware (which are all invoked for every request), while UseHandler is to set-up the terminal handler (only 1 is invoked for each request, or fallback to 404). If I understand the situation correctly then for some reason it's treating my terminal handlers as middlewares.
From the UseHandler documentation (https://godoc.org/github.com/urfave/negroni#Negroni.UseHandler)
UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
So it seems what you are seeing here is the expected behaviour.
You are basically creating different negroni instances and chaining them, so your final negroniStack is a middleware itself which will execute the other middlewares you added.
I believe what you want to do is create routes using an actual router, then add the appropriate middleware (using negroni) to each route.
If you look at the example you linked from the docs, that's what they are doing in that section (https://github.com/urfave/negroni#route-specific-middleware).
router.PathPrefix("/admin").Handler(negroni.New(
Middleware1,
Middleware2,
negroni.Wrap(adminRoutes),
))
See that they are not nesting negroni instances but rather creating just one which is applied to the desired routes.

axios does not send POST to golang api

I have a golang api backend with a negroni middleware.
I already implemented the CORS handler for negroni, so my api should allow cross origin resource sharing.
// allow OPTIONS method of CORS requests
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://127.0.0.1"},
})
//common.StartUp() - Replaced with init method
// Get the mux router object
router := routers.InitRoutes()
// Create a negroni instance
n := negroni.Classic()
n.Use(c)
n.UseHandler(router)
server := &http.Server{
Addr: common.AppConfig.Server,
Handler: n,
}
log.Println("Listening...")
server.ListenAndServe()
This is from the https://github.com/rs/cors/blob/master/examples/negroni/server.go example of implementing CORS with negroni.
Nevertheless my api now responses a 200 status back to my frontend, but the frontend does not send the POST request to the server. This my axios code:
import axios from 'axios';
const data = {
email: 'user#mail.com',
password: 'secret',
};
export default {
name: 'Login',
methods: {
login() {
axios.post('https://127.0.0.1:8090/users/login', data);
},
Postman does not have any problems with sending the POST request. What am I doing wrong?
Okay I found a solution for the problem:
As described in this article, I added some more options to the cors negroni plugin. One important option that was missing in my application was the line
AllowedHeaders: []string{"X-Auth-Key", "X-Auth-Secret", "Content-Type"},
Because my app sent the Content-Type Header and the api refused it.
I hope this will help others with similar problems.

Making golang Gorilla CORS handler work

I have fairly simple setup here as described in the code below. But I am not able to get the CORS to work. I keep getting this error:
XMLHttpRequest cannot load http://localhost:3000/signup. 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:8000' is therefore not allowed access. The
response had HTTP status code 403.
I am sure I am missing something simple here.
Here is the code I have:
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
log.Fatal(http.ListenAndServe(":3000", handlers.CORS()(router)))
}
Please read the link Markus suggested, and also about what triggers CORS pre-flight requests.
Pre-flight requests: You may have a content type like JSON, or some other custom header that's triggering a pre-flight request, which your server may not be handling. Try adding this one, if you're using the ever-common AJAX in your front-end: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With
Gorilla's handlers.CORS() will set sane defaults to get the basics of CORS working for you; however, you can (and maybe should) take control in a more functional manner.
Here's some starter code:
// Where ORIGIN_ALLOWED is like `scheme://dns[:port]`, or `*` (insecure)
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{os.Getenv("ORIGIN_ALLOWED")})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
// start server listen
// with error handling
log.Fatal(http.ListenAndServe(":" + os.Getenv("PORT"), handlers.CORS(originsOk, headersOk, methodsOk)(router)))
You can get more details here: Why doesn’t Postman get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when my JavaScript code does? about this issue.
Also try this handler: Go Cors Handler which should solve your issue. I find this much cleaner and easy to resolve the issue.
package main
import (
"log"
"net/http"
"github.com/rs/cors"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8000"},
AllowCredentials: true,
})
handler := c.Handler(router)
log.Fatal(http.ListenAndServe(":3000", handler)
}
You should create a CORSOption object. For example to allow any origin, Use this code:
corsObj:=handlers.AllowedOrigins([]string{"*"})
Then you pass this object to your handle.CORS function:
log.Fatal(http.ListenAndServe(":3000", handlers.CORS(corsObj)(router)))
For testing it you can use CURL:
curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://127.0.0.1:3000
When it works you should see those headers:
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
Final code is here: https://play.golang.org/p/AOrlJsWhvf
More info:
AllowedOrigin function
How can you debug a CORS request with cURL?
I realize this is an old issue but nonetheless it took me 30min to get this right.
handler = handlers.CORS(
// handlers.AllowedMethods([]string{"GET", "POST", "PUT"}),
handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"}),
// handlers.AllowedOrigins([]string{"*"}),
)(handler)
Things to note:
AllowedMethods does NOT need to explicitly include OPTIONS, this is part of the CORS handler
AllowedHeaders need to be explicitly mentioned, * is not a valid wildcard. Typical ajax libraries will send Content-Type when requesting something like application/json, so add that as well.
* is the default for AllowedOrigin
After declaring the mux object, add the accessControlMiddleware as a middleware to the declared object.
func main(){
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.Use(accessControlMiddleware)
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
// access control and CORS middleware
func accessControlMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS,PUT")
w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")
if r.Method == "OPTIONS" {
return
}
next.ServeHTTP(w, r)
})
}
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
"github.com/rs/cors"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
//cors optionsGoes Below
corsOpts := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8100"}, //you service is available and allowed for this base url
AllowedMethods: []string{
http.MethodGet,//http methods for your app
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodOptions,
http.MethodHead,
},
AllowedHeaders: []string{
"*",//or you can your header key values which you are using in your application
},
})
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
Base on jeremiah.trein's answer.
CORS filters are set on server side. Request may work with Postman and fail with a browser because Postman doesn't send preflight request whereas a browser does.
Setting the CORS filters will allow you to configure the origins, methods and headers that the backend shall accept.
In addition, if your browser emits POST or PUT requests that contain a json payload (which is quite reasonnable), you'll need to add 'Content-Type' to the allowed headers.
Finally the handlers.CORS()(router) does not only work with the http.ListenAndServe function but also with http.Handle().
The snippet of code might as well look like:
router := mux.NewRouter()
// do all your routes declaration
headersOK := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOK := handlers.AllowedOrigins([]string{"*"})
methodsOK := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS", "DELETE", "PUT"})
http.Handle("/", handlers.CombinedLoggingHandler(os.Stderr, handlers.CORS(headersOK, originsOK, methodsOK)(router)))
It is worth mentionning that i have successfuly used this snippet of code in a Google Cloud Platform Standard AppEngine (and I believe it would work in a Flex AppEngine as well).
The aformentioned package github.com/rs/cors provides a constructor
AllowAll() *Cors
that
...create a new Cors handler with permissive configuration allowing all
origins with all standard methods with any header and credentials.

Resources