When troubleshooting an API request from a browser, I find it useful to inspect the CORS headers directly with curl. It makes it easier to see what the server is returning.
For a cross-origin JSON POST request with an authorization header, start by simulating the browser's preflight request:
curl -i -X OPTIONS 'https://api.example.com/endpoint' \
-H 'Origin: https://example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type, authorization'
Replace both URLs with your API endpoint and frontend origin. An illustrative successful response could look like this:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: content-type, authorization
Vary: Origin
Next, test the actual POST request:
curl -i 'https://api.example.com/endpoint' \
-H 'Origin: https://example.com' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--data '{"message":"Testing CORS"}'
Use a suitable test endpoint and payload: this sends a real POST request. Replace the token if authentication is required, or remove that header if it isn't.
Notice that the Access-Control-Request-* headers belong to the preflight. The actual POST carries the content type and authorization header themselves.
An example POST response might be:
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: https://example.com
Vary: Origin
{"message":"Request received"}
Check the CORS headers on both responses. A successful preflight alone isn't enough if the actual response is missing the required headers.
For browser requests made with credentials, such as cookies using credentials: 'include', the server must allow the specific origin and return Access-Control-Allow-Credentials: true; a wildcard origin won't work for those requests.
Finally, curl displays the response but doesn't enforce CORS like a browser does. Confirm the behavior in your browser too. The MDN CORS guide explains how the browser evaluates these responses.
Hope you found this tip useful!