The Short Answer
CORS is a browser permission check. It does not show that the endpoint is offline. Compare a command-line request with the browser preflight.
- 1
Confirm that the same operation works outside the browser.
- 2
Inspect the browser
OPTIONSrequest and response. - 3
Allow the exact origin, method, and required request headers.
- 4
Do not put long-lived provider credentials in public browser code.
Inspect the Preflight Response
An authenticated JSON request normally triggers a preflight. Test the same origin and request headers that the browser will use.
curl -i -X OPTIONS https://api.example.com/v1/chat/completions \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: authorization,content-type"Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Vary: OriginRead the browser rules in the MDN CORS guide.
Map the Browser Error to the Missing Permission
| Symptom | Likely problem | Check next |
|---|---|---|
| No allow-origin header | Origin is not allowed | Exact scheme, host, and port |
| Method is not allowed | POST or OPTIONS missing | Allowed methods |
| Header is not allowed | Authorization or content type missing | Allowed headers |
| Preflight returns 404 | OPTIONS route missing | Gateway and server routing |
| curl works; browser fails | Browser policy | Preflight response |
| Both requests fail | Endpoint or configuration | DNS, TLS, route, and auth |
Choose a Safe Execution Route
Use browser-direct requests for localhost or private endpoints. Configure their CORS policy for the testing page origin.
Use a controlled server proxy for public endpoints when browser access is not required. The proxy must protect credentials and block internal network targets.
no-cors does not grant response accessThe browser can send an opaque request, but JavaScript cannot read the status, headers, or response body.
Verify CORS and Endpoint Health Separately
LLMCompat can compare a browser-direct attempt with a protected server route. Local and private endpoints always stay browser-direct.