In the below investigation as API, I use http://example.com instead of http://myApiUrl/login from your question, because this first one working.
I assume that your page is on http://my-site.local:8088.
The reason why you see different results is that Postman:
- set header
Host=example.com
(your API) - NOT set header
Origin
This is similar to browsers' way of sending requests when the site and API has the same domain (browsers also set the header item Referer=http://my-site.local:8088
, however I don't see it in Postman). When Origin
header is not set, usually servers allow such requests by default.

This is the standard way how Postman sends requests. But a browser sends requests differently when your site and API have different domains, and then CORS occurs and the browser automatically:
- sets header
Host=example.com
(yours as API) - sets header
Origin=http://my-site.local:8088
(your site)
(The header Referer
has the same value as Origin
). And now in Chrome's Console & Networks tab you will see:


When you have Host != Origin
this is CORS, and when the server detects such a request, it usually blocks it by default.
Origin=null
is set when you open HTML content from a local directory, and it sends a request. The same situation is when you send a request inside an <iframe>
, like in the below snippet (but here the Host
header is not set at all) - in general, everywhere the HTML specification says opaque origin, you can translate that to Origin=null
. More information about this you can find here.
fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab
If you do not use a simple CORS request, usually the browser automatically also sends an OPTIONS request before sending the main request - more information is here. The snippet below shows it:
fetch('http://example.com/api', { method: 'POST', headers: { 'Content-Type': 'application/json'} });
Look in chrome-console -> network tab to 'api' request. This is the OPTIONS request (the server does not allow sending a POST request)
You can change the configuration of your server to allow CORS requests.
Here is an example configuration which turns on CORS on nginx (nginx.conf file) - be very careful with setting always/"$http_origin"
for nginx and "*"
for Apache - this will unblock CORS from any domain.
location ~ ^/index\.php(/|$) { ... add_header 'Access-Control-Allow-Origin' "$http_origin" always; add_header 'Access-Control-Allow-Credentials' 'true' always; if ($request_method = OPTIONS) { add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above) add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin'; add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain charset=UTF-8'; return 204; } }
Here is an example configuration which turns on CORS on Apache (.htaccess file)
# ------------------------------------------------------------------------------ # | Cross-domain Ajax requests | # ------------------------------------------------------------------------------ # Enable cross-origin Ajax requests. # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity # http://enable-cors.org/ # <IfModule mod_headers.c> # Header set Access-Control-Allow-Origin "*" # </IfModule> # Header set Header set Access-Control-Allow-Origin "*" # Header always set Access-Control-Allow-Credentials "true" Access-Control-Allow-Origin "http://your-page.com:80" Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT" Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"