Crossing the CORS crossroad
rednafi opened this issue · comments
Redowan Delowar commented
- Briefly explain the CORS workflow
- Maybe add a simple mermaid sequence diagram to explain it
- Write a quick server that allows requests only from a list of allowed origins
- Demonstrate how to make preflight options requests with curl to verify that the server only allows requests from certain origins
package main
import (
"encoding/json"
"fmt"
"net/http"
)
// Person struct to parse the input JSON
type Person struct {
Name string `json:"name"`
}
// helloNameHandler responds with "Hello {name}".
func helloNameHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
return
}
var p Person
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
response := fmt.Sprintf("Hello %s", p.Name)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": response})
}
// corsMiddleware adds CORS headers to the response
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
allowedOrigins := map[string]bool{
"http://allowed-origin-1.com": true,
"http://allowed-origin-2.com": true,
}
origin := r.Header.Get("Origin")
if _, ok := allowedOrigins[origin]; ok {
w.Header().Set("Access-Control-Allow-Origin", origin)
} else {
// Optional: Handle not allowed origin, e.g., by returning an error
http.Error(w, "Origin not allowed", http.StatusForbidden)
return
}
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
// Handle preflight request
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.Handle("/hello", corsMiddleware(http.HandlerFunc(helloNameHandler)))
fmt.Println("Server is running on http://localhost:7676")
http.ListenAndServe(":7676", mux)
}
Run the server with go run main.go
.
Make a preflight request with the correct header:
curl -X OPTIONS http://localhost:7676/hello -d '{"name": "Thing"}' -i -H 'Origin: http://allowed-origin-1.com'
HTTP/1.1 200 OK
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Origin: http://allowed-origin-1.com
Date: Tue, 12 Mar 2024 16:08:26 GMT
Content-Length: 0
Make a preflight request with incorrect header:
curl -X OPTIONS http://localhost:7676/hello -d '{"name": "Thing"}' -i -H 'Origin: http://notallowed.com'
HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Tue, 12 Mar 2024 16:11:57 GMT
Content-Length: 19
Origin not allowed