AWS API Gateway - CORS POST not working
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When a browser says your API Gateway POST request is blocked by CORS, the failure is usually not the POST itself. The real problem is that the browser first sends a preflight OPTIONS request, and either that response is wrong or the eventual POST response is missing the required CORS headers.
Why POST Often Triggers a Preflight Request
Simple cross-origin requests can go straight through, but many real POST requests are not "simple" from the browser's perspective. JSON bodies, Authorization headers, and custom headers commonly trigger a preflight check.
The browser sends:
If the server does not respond with matching CORS headers, the browser never sends the real POST.
That is why Postman can succeed while the browser still fails. Postman is not enforcing browser CORS rules.
You Need CORS on Both OPTIONS and POST
A common mistake is configuring CORS only for the preflight route. The browser also checks the actual POST response.
At minimum, the actual response should include headers such as:
- '
Access-Control-Allow-Origin' - optionally
Access-Control-Allow-Credentials
If you are using Lambda proxy integration, your function usually needs to return those headers itself:
For the preflight route, API Gateway can return the response directly or your backend can do it, depending on how the API is set up.
A Good Mental Model for API Gateway CORS
Think of CORS in API Gateway as two checks:
- Can the browser send the request at all
- Is the actual response allowed to be read by the page
The first check is the OPTIONS preflight. The second check is the final POST response.
If either one is missing headers, the browser reports a CORS failure.
Error Responses Must Also Carry CORS Headers
This catches a lot of teams. They configure the successful 200 response correctly, but when the Lambda throws, API Gateway returns 4xx or 5xx without CORS headers.
From the browser, that still looks like "CORS is broken," even though the real application error might be unrelated.
So you need to make sure:
- success responses include CORS headers
- validation errors include CORS headers
- unauthorized responses include CORS headers
- integration failures include CORS headers
If you skip the error paths, debugging becomes confusing very quickly.
Authorizers and Authentication Can Break Preflight
Another common issue is requiring authentication on OPTIONS. Preflight requests are supposed to be a lightweight permission check from the browser, so if the OPTIONS route is blocked by an authorizer or missing configuration, the browser never gets past the preflight stage.
That is why many API Gateway CORS fixes come down to:
- allow anonymous
OPTIONS - return the exact methods and headers the browser asked for
- deploy the stage after making the change
The deploy step matters. In API Gateway, configuration changes are easy to make and just as easy to forget to deploy.
How to Debug It Quickly
Use browser developer tools and inspect the Network tab. Look for:
- whether
OPTIONSwas sent - the status code of the preflight response
- the presence of
Access-Control-Allow-Origin - the allowed methods and headers returned
Then compare that with the real POST response. If OPTIONS succeeds but POST still fails, the final response headers are usually the missing piece.
From the command line, you can also simulate the preflight:
This does not replace browser testing, but it is a fast way to confirm what API Gateway is actually returning.
Common Pitfalls
- Configuring CORS for
OPTIONSonly and forgetting the realPOSTresponse. - Testing in Postman and assuming that means browser CORS is configured correctly.
- Protecting the
OPTIONSroute with authentication or an authorizer. - Returning wildcard origin together with credentials, which browsers reject.
- Forgetting to deploy the API Gateway stage after changing CORS settings.
Summary
- A broken
POSTCORS flow is often really a broken preflightOPTIONSresponse. - Both the preflight response and the real
POSTresponse need correct CORS headers. - Error responses need CORS headers too, not just successful ones.
- '
OPTIONSshould usually be accessible without normal request authentication.' - The fastest debug path is checking the browser Network tab and comparing
OPTIONSwithPOST.

