The following notes gathered from various sources helped me as a CORS beginner (which I still most definitely am) - so, maybe they will also help others.
Also, I am sure the following notes are far from the full story. And like @amon said, reverse proxying is also a way to solve for (i.e. sidestep) CORS.
1) That CORS Flowchart
See this question - the flowchart shown there is a summary describing who sends what. However, as a beginner, I found the flowchart initially difficult to understand in isolation.
I looked at this guide, which provides a lot more technical details on who can send which headers. For example, the second of its three scenarios shows who sends what for a request which includes a preflight request:

Three examples where preflighting is required are:
- the request includes an authentication token
- custom headers are included in the request
- the request is an ajax call containing a JSON or XML payload.
In contrast, requests containing plain GET
s are not preflighted.
One key point here is it is the browser - not the client application - which manages these interactions from the browser to the server. The client application has no direct involvement in these interactions.
On the server, it is typically a CORS filter which controls the contents of the response from the server back to the browser (an example is provided below).
That might be all you need to get a reasonably complete answer to the "who sends what" question. But I was still confused.
I looked at an example, which helped me much more - see below.
I think the best insight I had, along the way, was that my client application did not need to do anything specific to address CORS restrictions. It was the browser in which my application was running which took care of client-side CORS handling. As @amon says, CORS is not intended to protect resources, but to help browsers protect users against malicious websites.
2) An Example
Looking at a specific example helped my understanding of who sends what.
Scenario: We have a client application running in a browser, at https://domainA.com
. It makes an API request to an unrelated server (http://anotherdomainX.net
).
The example server I show here is Tomcat - other servers may have significantly different ways of configuring a CORS filter (I don't know). But the Tomcat example lays out a lot of the details in a relatively clear way.
See this ServerFault question for the example.
This is the XML from that example:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>
http://domainA.com,
https://domainA.com,
http://localhost:4200
</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>
Content-Type,
X-Requested-With,
Accept,
Accept-Encoding,
Accept-Language,
Origin,
Access-Control-Request-Method,
Access-Control-Request-Headers,
Connection,
Host,
authorization
</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>
Access-Control-Allow-Origin,
Access-Control-Allow-Credentials
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(For Tomcat, this is added to the web.xml
config file in CATALINA_HOME/conf
.)
The various sections in the above filter are documented here (Tomcat 9).
But the key point is it is the above filter definition which controls what specific CORS-related are returned from the server.
The cors.allowed.origins
section is where the whitelist is defined. By default, the list is empty, meaning no requests get through, except those from the same domain (origin) as the server - http://anotherdomainX.net
.
3) Origin Names
This is basically what you see in the address bar of your client web-based application. It has to include the protocol, domain name and port number (if used). The root of the application context is not part of the origin name.
So, for a URL such as https://domainA.com/myapp/getdata
, then https://domainA.com
is the origin name.
4) Postman
This appears to crop up fairly frequently. Why does my API call work in Postman, but not from my web client?
The basic answer is because Postman is a dev tool, not a browser.
My understanding is that it uses browser extensions, which have different rules regarding how XMLHttpRequest
s are handled.
Tools such as cURL are also not relevant for CORS because again as @amon says, CORS is not intended to protect resources, but to help browsers protect users against malicious websites.
5) null Origins
An example of a null origin is when you create a simple web page in a text file, open it in a browser, and have a URL like this:
file:///C:/temp/test.htm
Here the protocol is file:
. See here for notes and warnings about this.
6) Public APIs
It's probably bad form for an answer to contain a question, but...
How do publicly available services handle CORS? Do they just enable "everyone" in their cors-allowed-origins
?
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value> * </param-value>
</init-param>
I guess the answer is yes. In its "common pitfalls" section, the linked article states:
CORS is a relaxation of same-origin policy while attempting to remain secure. Using * disables most security rules of CORS. There are use cases where wildcard is OK such as an open API that integrates into many 3rd party websites.
I would be delighted to edit the above notes to correct any errors, if that is appropriate.