A preflight is answered with the headers it asked about

The allow-list named Content-Type and nothing else, and a browser refuses the
entire request over one header missing from it. The exchange sends x-api-key, so
every call to /v1/quote and /v1/swappable_tokens failed its preflight and the
swap panel had neither a token list nor a price.

A literal "*" is not the fix. Safari does not honour the wildcard in this header
and refuses in exactly the same way — which is how a header set to "*" elsewhere
in this stack still produced "x-api-key is not allowed by
Access-Control-Allow-Headers". Echoing the request's own
Access-Control-Request-Headers is precise, needs no maintenance as clients add
headers, and every browser understands it.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
2026-08-13 22:39:33 -07:00
co-authored by Hanzo Dev
parent 71c1ff73fd
commit c8725690c3
+10 -1
View File
@@ -275,7 +275,16 @@ func securityMiddleware(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")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
// The headers the request actually asked about, rather than a list of
// the ones someone thought to name. A browser refuses the whole call
// over one missing name — the exchange sends x-api-key — and a literal
// "*" does not help, because Safari does not honour the wildcard here.
if asked := r.Header.Get("Access-Control-Request-Headers"); asked != "" {
w.Header().Set("Access-Control-Allow-Headers", asked)
} else {
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
}
w.Header().Set("Vary", "Origin, Access-Control-Request-Headers")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Cache-Control", "no-store")