The CORS Header Was Right There and the Browser Blocked It Anyway
The browser console showed exactly what CORS errors always show — a request blocked for violating the same-origin policy — except the response headers, visible in the network tab, clearly included Access-Control-Allow-Origin: * . The header the browser wanted was right there. The browser rejected the request anyway. The detail that's easy to miss in the network tab Chrome's network inspector, by…
Browser console displayed standard CORS error indicating a blocked request for violating same-origin policy, despite the presence of an Access-Control-Allow-Origin: * header in response headers. Chrome's network inspector automatically merges duplicate header names, potentially leading to confusion as it displays a single line for duplicated headers, such as Access-Control-Allow-Origin: * which may actually represent two separate headers sent by different layers.
One nginx reverse proxy sent a blanket Access-Control-Allow-Origin: * header for general API access, while the application server also independently set a specific origin for authenticated routes. Both configurations were technically correct on their own, but together they resulted in a response containing two identical Access-Control-Allow-Origin headers.
According to the Fetch specification, multiple Access-Control-Allow-Origin values in a response are considered invalid, causing the browser to block the request regardless of the header's correctness. This situation is worse than a missing header because a missing header fails predictably and consistently, whereas a duplicate header can mask the issue, presenting a legitimate-looking response that still fails.
To resolve this, the fix involved removing the redundant nginx header, allowing the application server to become the sole authority for CORS decisions. By consolidating CORS configuration to a single layer, the risk of duplicated headers is eliminated, ensuring the header's correctness and preventing requests from being blocked.
This type of bug, where multiple infrastructure layers independently configure headers, often goes unnoticed until the response fails. To avoid such issues, it's recommended to keep ingress configurations minimal, with only one authoritative layer responsible for CORS settings, whether it's your application or the reverse proxy.
To investigate such issues, first capture the response headers using curl -sD - against the failing endpoint and use grep -i access-control to verify the presence and duplication of the Access-Control-Allow-Origin header.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.