CORS is an important security mechanism to prevent malicious cross-origin requests. It’s also confusing for developers, with cryptic error messages and seemingly endless configuration options.
In this article, we’ll uncover precisely why CORS exists, how it works, and how best to setup the browser and server for secure cross-origin communication.
1. What problem does CORS solve?
To understand CORS you need to understand the concept of an origin.
Origin: a specific protocol, host, and port combination
An example of an origin is https://www.google.com:443
. That’s the same as https://www.google.com
shown in the browser address bar, which assumes port 443
by default.
An example of a different origin is https://apis.google.com:443
. Even though this origin contains the same google.com
base domain as https://www.google.com:443
, it has an apis
subdomain, which makes it unique.
Get the idea? 🤔
To put it another way, the origin is the part of the URL before the path. It determines which server a request is sent to, since the domain name resolves to an IP address, via a DNS lookup. Every HTTP request made from a webpage in a browser has an origin.
Origins and HTTP requests
When you access the webpage at https://www.theguardian.com/international
in your browser, this is the origin:
Request URL | Origin |
---|---|
https://www.theguardian.com:443/international | https://www.theguardian.com |
This initial request returns an HTML document, which itself makes further requests. But this time, to another origin:
So the main https://www.theguardian.com:443/international
document makes requests to other origins. We call these cross-origin requests.
How do you know if a request is cross-origin?
Check the origin part of the website URL shown in the browser address bar. If it’s different from the origin part of the request URL, you’re cross-origin, baby!
Determining cross-origin requests in a browser
In fact, most websites make such cross-origin requests.
Why?
Three main reasons:
-
it’s convenient to store assets like JavaScript, images, and CSS on a different server
-
it’s clearer to host different parts of a website on different subdomains e.g.
https://apis.google.com:443
-
JavaScript code may need to make API calls to other 3rd party services
OK, so websites need to make requests to different origins. So what?
Browser default behaviour
Well, depending on the webpage resource from which the cross-origin request originates, the browser may or may not allow it.
Browsers by default allow cross-origin requests from:
-
Image
<img src="...">
tags (see example) -
CSS
<link rel="...">
tags (see example) -
JavaScript
<script src="...">
tags (see example) -
some less common resources (see full list)
But, browsers by default deny cross-origin requests from:
-
JavaScript code using the
fetch
API orXMLHttpRequest
-
some less common resources (see full list)
This policy is known as the same origin policy. Browsers implement it to prevent certain attacks, where malicious websites run JavaScript code requesting data from other websites.
For example, without the same origin policy, a dodgy website could make a request to https://api.your-bank.com
, get all your account information, then send it back to their dodgy server.
The same origin policy prevents cross-origin JavaScript requests
But making cross-origin requests through JavaScript is a very common requirement for modern websites e.g. https://example.com
calls https://api.example.com
. This is the main use case we’ll explore in this article.
But before we get into how CORS enables cross-origin requests, how did webpages work before CORS?
2. What happened before CORS?
Before CORS, cross-origin requests from JavaScript code had to be made to the same origin.
If you think that was a big problem, you’re right! Web developers were restricted in the experiences they could create, but still had a few options available:
-
form data could be posted cross-origin
-
images, CSS, and scripts could still be loaded from another origin
-
servers were free to make requests to any origin they liked
Although such workarounds existed, many developers felt that the same origin policy was too restrictive. Even though it helped prevent malicious cross-origin attacks, surely there was an alternative?
Fortunately, in 2009, a way to relax this same-origin restriction was introduced, called CORS.
3. How does CORS work?
Cross-Origin Resource Sharing (CORS) is a relaxing of the same origin policy rules. With CORS, and under certain conditions, browsers allow JavaScript code running on a site from one origin to send requests to another origin.
With CORS, it’s up to the server to decide which cross-origin requests are allowed.
That’s great, because now an API hosted at https://api.your-bank.com
can allow cross-origin requests from https://your-bank.com
, but block requests from https://super-dodgy.com
. 👍
With CORS, the API chooses which cross-origin requests are allowed
So how does CORS actually work?
Well, there are 2 main parts to it:
-
the browser: detects when JavaScript code tries to make a cross-origin request, and intercepts that request either before it’s sent, or before the response is returned
-
the server: tells the browser which origins are allowed to make requests, by sending back special CORS HTTP headers
HTTP headers are key-value pairs that get sent in the HTTP request, along with the method and body.
Fortunately, the browser component of CORS is mostly taken care of automatically. For example, Chrome intercepts requests made from JavaScript, and validates with the server that they’re acceptable.
Most of the CORS configuration that developers need to make is on the server. That makes sense, since the server is in charge of deciding which cross-domain requests to allow.
But before learning how to configure the server for CORS, we need to explore in detail what happens when the browser intercepts a cross-origin request. Depending on the type of request, the browser will deal with it in one of two distinct ways.
-
simple requests: send the original request and validate CORS headers on the response
-
pre-flighted requests: send a pre-flight request, validate it, then send the original request
Let’s explore these two approaches in more detail.
Approach 1: Browser validates origin on response
With this approach, the browser sends the cross-origin request without any up-front checks.
When the response is received, the browser looks for a specific header, Access-Control-Allow-Origin
. This header, sent by the server, tells the browser which origins are allowed to handle the request.
Access-Control-Allow-Origin <origin>
The value of the header can be a single origin, or *
to represent any origin.
On inspecting this header, the browser has to deal with 3 possibilities:
-
the response has an
Access-Control-Allow-Origin
header, and it contains the origin from which the cross-origin request was made. The browser accepts the response and the JavaScript code gets access to it. -
the response has an
Access-Control-Allow-Origin
header, but it doesn’t contain the origin from which the cross-origin request was made. The browser rejects the response, and the JavaScript code gets an error. -
the response doesn’t have an
Access-Control-Allow-Origin
header. The browser rejects the response, and the JavaScript code gets an error.
So the browser works out whether the request comes from a valid origin, thanks to the header sent from the server. This approach is used when the request is a simple request.
Simple requests are:
-
GET
with only default headers (discussed later) -
HEAD
-
POST
whereContent-Type
isapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
An example
Consider what happens when a GET
request is made from a webpage at the origin https://corsexamples.tomgregory.com
to an API at the origin https://api.corsexamples.tomgregory.com
.
Request headers
Origin: https://corsexamples.tomgregory.com
The browser sets many other headers automatically, but Origin
is the most relevant right now.
Once the server receives the request, it sends this response.
Response status code
200 OK
Response headers
Access-Control-Allow-Origin: https://corsexamples.tomgregory.com
Response body
{"message":"Success response from GET request"}
In this case, the server responded with the Access-Control-Allow-Origin
header, with a value equal to the request origin. The browser accepts the response, passing it to the JavaScript code, which continues execution.
Try this example in the Interactive CORS Simulator.
Does JavaScript know about CORS? From JavaScript’s perspective, CORS doesn’t exist. It’s all handled by the browser. So when you call fetch(<request-url>)
, either a response is returned or an error is thrown, depending on the result of the CORS check.
Approach 2: Browser validates origin in pre-flight request
The other approach the browser uses to allow cross-origin requests applies to all other requests types, including:
POST
(whereContent-Type
is notapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
)PUT
PATCH
DELETE
Since these types of request might manipulate data on the server-side, they must be validated by the browser before the request is sent to the server. This is achieved with another request, called a pre-flight request, sent automatically to the server by the browser.
The pre-flight request is a special OPTIONS
type request, which the server must be able to handle.
The browser automatically adds these headers to the pre-flight request:
Origin
: as described aboveAccess-Control-Request-Method
: specifies the HTTP method the browser will use in the main requestAccess-Control-Request-Headers
: specifies the headers the browser will send in the main request
These headers are a way for the browser to tell the server what to expect in the main request. If the details match what the server allows, the server should respond with full details of what requests are acceptable.
The server adds these headers on the response to the pre-flight request:
Access-Control-Allow-Origin
: specifies the origin from which the main request may be madeAccess-Control-Allow-Methods
: specifies allowed methods for the main requestAccess-Control-Allow-Headers
: specifies allowed headers for the main request
The browser checks the pre-flight response to decide if the main request can be made. If it can, it makes it and passes the response to the JavaScript code. Otherwise, the browser doesn’t make the main request, and instead returns an error to the JavaScript code.
Note that the pre-flight response headers can include values that weren’t in the request headers. Why? Because the pre-flight response includes all available headers and methods for the specific path. As you’ll see later, this enables the pre-flight response to be cached to avoid future pre-flight requests.
Error response to pre-flight request: During the pre-flight request, the server may determine that the provided CORS headers are invalid. It can then return a 403 Forbidden response, which will cause the browser to reject the main request and return an error to the JavaScript code.
e.g. if the browser sends Access-Control-Request-Method: DELETE
in the pre-flight request, but the server only accepts POST
requests, it can return a 403
error.
An example
Consider what happens when a POST
request is made from a webpage at the origin https://corsexamples.tomgregory.com
to an API at the origin https://api.corsexamples.tomgregory.com
.
Since this is a POST
request with a Content-Type
of application/json
, the browser intercepts the request to send a pre-flight OPTIONS
request.
PRE-FLIGHT REQUEST
Request headers
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: https://corsexamples.tomgregory.com
The browser includes CORS headers in the request, with values describing the cross-origin request that the JavaScript code wants to make.
The server returns this response to the pre-flight request:
PRE-FLIGHT REQUEST
Response headers
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Origin: https://corsexamples.tomgregory.com
This tells the browser that the main request can be made, since its origin, method, and headers are compatible.
So the browser makes the main request:
MAIN REQUEST
Request headers
Content-type: application/json
Origin: https://corsexamples.tomgregory.com
The server processes the request, and sends this response:
MAIN REQUEST
Response status code
200 OK
Response headers
Access-Control-Allow-Origin: https://corsexamples.tomgregory.com
Response body
{"message":"Success response from POST request"}
In this case, the browser accepts the response and returns it to the JavaScript code.
Did you notice how the server includes the Access-Control-Allow-Origin
header in the response to the main request too? If this header isn’t set correctly, the browser can still reject the response and return an error to the JavaScript code.
Try this example in the Interactive CORS Simulator.
4. Do CORS requests include headers?
CORS has strict rules about what request headers can be sent to and returned from another origin.
Request headers
Without any additional configuration, only the following headers are allowed:
Accept
Accept-Language
Content-Language
Content-Type
with a value ofapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
So what to do if you want to send other headers?
Again, the API defines what headers can be included. The server tells the browser this through the Access-Control-Allow-Headers
header, included in the response to the pre-flight request.
The value must be a comma-separated list of allowed header names.
Access-Control-Allow-Headers: <header name 1>,<header name 2>,...
For example, suppose we run this JavaScript code to make a cross-origin GET
request, including a custom header:
fetch("https://api.corssimulator.tomgregory.com/get-allow-header", {
headers: {
Cool-Stuff: "pi=3.14"
},
});
Since this GET
request has a custom header, it’s no longer a simple request and the browser sends an additional pre-flight request.
PRE-FLIGHT REQUEST
Request headers
Access-Control-Request-Headers: cool-stuff
Access-Control-Request-Method: GET
Origin: https://corssimulator.tomgregory.com
The browser automatically adds Access-Control-Request-Headers
, with a value based on the fetch
function call.
The server processes this, and returns this response:
PRE-FLIGHT REQUEST
Response headers
Access-Control-Allow-Headers: cool-stuff
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: https://corssimulator.tomgregory.com
With this response, the server has told the browser that it’s permitted to send the main request with the custom header, which it does:
MAIN REQUEST
Request headers
cool-stuff: pi=3.14
Origin: https://corssimulator.tomgregory.com
Try this example in the Interactive CORS Simulator.
Simple vs. pre-flighted requests: you’ve seen that sending an additional header can trigger the browser to send a pre-flight request for a GET
request. To ensure you’ve got appropriate OPTIONS
APIs exposed, use a framework which creates these automatically, as discussed later.
Response headers
Just like CORS restricts what request headers can be sent in a cross-origin request, restrictions also exist on the response headers.
The difference is that the server can send any response headers it likes, but only the configured headers are exposed to the JavaScript code. In other words, the browser filters out disallowed response headers and constructs the JavaScript HTTP response as though they were never returned.
How does it work?
You guessed it, another CORS-specific response header! This time it’s Access-Control-Expose-Headers
, which takes a comma-separated list of response headers to be returned to the JavaScript code.
Access-Control-Expose-Headers: <header name 1>,<header name 2>,...
For example, suppose we have this JavaScript code, which makes a simple GET
request:
fetch("https://api.corssimulator.tomgregory.com/get-allow-header");
The request is sent cross-origin with the Origin
header:
Request headers
Origin: https://corssimulator.tomgregory.com
The server needs to expose a header to the calling JavaScript, so it sends this response back to the browser.
Response status code
200 OK
Response headers
Access-Control-Allow-Origin: https://corssimulator.tomgregory.com
Access-Control-Expose-Headers: Best-Header-Ever
Best-Header-Ever: If you're reading this, it worked!
Response body
{"message":"Success response from GET request"}
The Access-Control-Expose-Headers
header tells the browser that the specified header can be returned to the JavaScript code. The JavaScript code can then use the header value as required.
For example, the above code could be modified to log the header value:
fetch("https://api.corssimulator.tomgregory.com/get-allow-header")
.then(response => console.log(response.headers.get("Best-Header-Ever")));
Try this example in the Interactive CORS Simulator. There’s also an example for a pre-flighted request, which works in the same way.
Included response headers: to return any of these response headers to JavaScript, you don’t need to set the Access-Control-Expose-Headers
header: Cache-Control, Content-Language, Content-Length, Content-Type, Expires, Last-Modified, Pragma.
You’ve now seen several success-case CORS examples, for both simple and pre-flighted requests. But things don’t always go to plan, so let’s see what might go wrong with cross-origin requests.
5. Why do I get CORS errors in my browser?
Here are some common CORS-related errors you might see in the browser.
Error from GET request with missing header
When making a cross-origin GET
request you could get this error in the Chrome JavaScript console.
Access to fetch at ‘https://api.corssimulator.tomgregory.com/get-without-cors' from origin ‘https://corssimulator.tomgregory.com’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
In this case, the response was missing the Access-Control-Allow-Origin
header, so it was rejected by the browser. The browser must validate that the request origin matches the response header to pass the response back to the JavaScript code.
Resolution: add an Access-Control-Allow-Origin
header containing the origin https://corssimulator.tomgregory.com
Try this example in the Interactive CORS Simulator.
Error from GET request with misconfigured header
When making a similarGET
request, you might instead see this error.
Access to fetch at ‘https://api.corssimulator.tomgregory.com/get-misconfigured-origin' from origin ‘https://corssimulator.tomgregory.com’ has been blocked by CORS policy: The ‘Access-Control-Allow-Origin’ header has a value ‘https://archive.tomgregory.com’ that is not equal to the supplied origin.
This time, the server has returned the Access-Control-Allow-Origin
header, but it was misconfigured. Since the browser couldn’t match the request origin with the value in the header, the response was rejected.
Resolution: configure the Access-Control-Allow-Origin
header to have the origin https://corsexamples.tomgregory.com
Try this example in the Interactive CORS Simulator.
Error from POST request with missing OPTIONS
API
When making a POST
request with a Content-Type
of application/json
, the browser sends a pre-flight OPTIONS
request. If this API doesn’t exist, the server returns a 404 Not Found response, and the browser shows this message in the JavaScript Console.
Access to fetch at ‘https://api.corssimulator.tomgregory.com/post-no-options-api' from origin ‘https://corssimulator.tomgregory.com’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Notice how the error message doesn’t mention anything about the 404 Not Found response? In Chrome, to see the response details look in the Network tab (see next section for more details).
Resolution: add an OPTIONS
API, returning headers Access-Control-Allow-Methods
, Access-Control-Allow-Headers
, and Access-Control-Allow-Origin
.
Try this example in the Interactive CORS Simulator.
So you’ve seen a few error examples, but does this cover all the possibliites?
Actually, no, because there are just too many. But there are other ways to figure out what’s going on when you get a CORS issue.
6. How to debug CORS issues in the browser?
Let’s run through some techniques to diagnose CORS issues yourself, within the browser.
Diagnosing simple request problems
When your JavaScript code makes a simple request, which doesn’t require a pre-flight request, you can see helpful information in the JavaScript Console.
CORS error shown in Chrome’s JavaScript Console
In this case, the error is clearly described, telling us that the Access-Control-Allow-Origin
header has been incorrectly configured.
Diagnosing pre-flight request problems
For pre-flighted requests, we need to see details of the 2 separate network requests:
-
the pre-flight request
-
the main request
To view this information in Chrome of Firefox, open the Network tab in Developer Tools, accessed with F12.
CORS pre-flight and main request in Firefox’s Web Developer Tools
In this specific case, the pre-flight request has an error. Click the request to see more details
A 404 Not Found response was received from the pre-flight request. The server should be updated to implement an OPTIONS
API.
7. How to implement CORS on the server?
If you’ve followed the troubleshooting steps above, and you know what the problem is, what next?
To resolve almost all CORS issues, you’ll have to make changes to your API to:
-
include missing CORS headers
-
fix misconfigured CORS headers
-
add a missing
OPTIONS
API
What this involves depends on the technology your API uses. For example, you might need to add code to set a header name and value, or configure a framework to do it for you.
To help you out, here’s how you can configure CORS using 3 popular API technologies.
Implement CORS in Spring Boot
The Java Spring Boot framework can automatically add the required CORS headers to the response and expose an OPTIONS
API to service pre-flight requests. You just need to configure which endpoints should be cross-origin enabled.
You can do that at the API level, on an individual controller method, with the @CrossOrigin
annotation:
@CrossOrigin
@GetMapping(value = "/ride", produces = MediaType.APPLICATION_JSON_VALUE)
public Iterable<ThemeParkRide> getRides() {
return themeParkRideRepository.findAll();
}
Or at the global level, by adding a WebMvcConfigurer
configuration bean to a @SpringBootApplication
or @Configuration
class.
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
Each of these approaches also lets you cofigure the allowed origins, methods, and headers.
Here’s how the API-level annotation looks to set an allowed origin:
@CrossOrigin(origins = "https://corssimulator.tomgregory.com")
Implement CORS in JavaScript
If you’re writing an API in JavaScript, simply return the required CORS headers by setting them in code.
Here’s an example in a Node.js handler for a simple GET
request, designed to run in AWS Lambda.
module.exports.handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify(
{
message: 'Success response from GET request'
}
),
headers: {
"Access-Control-Allow-Origin": "*",
}
};
};
For requests requiring a pre-flight request, you can simply check the request method, then return a different response if it’s OPTIONS
.
module.exports.handler = async (event) => {
const allowedOrigins = "*";
const allowedHeaders = "*";
if ('OPTIONS' === event.requestContext.http.method) {
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": allowedOrigins,
"Access-Control-Allow-Headers": allowedHeaders,
}
};
}
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": allowedOrigins,
},
body: JSON.stringify(
{
message: 'Success response from POST request'
}
)
};
};
This approach is more manual than other frameworks, such as Spring Boot, but it gives you ultimate control. The responses to the APIs called by the Interactive CORS Simulator use this approach.
Implement CORS in AWS
One way to move CORS logic out of the code and into the infrastrcture is to use AWS API Gateway. It’s like a load balancer, routing requests to AWS Lambda functions, which run code. Importantly, it has a Configure CORS page.
Here you set values for the different CORS headers, which API Gateway then adds automatically to any Lambda function response. It also adds an appropriate pre-flight OPTIONS
API.
Configuring CORS in AWS API Gateway
The benefit of using this approach is that once it’s setup, additional API Gateway routes will automatically inherit this CORS configuration.
8. Do CORS requests include cookies?
One security vulnerability with cross-origin requests is where a malicous website sends an authenticated JavaScript request to an API at another origin. The request could include cookies, providing access to sensitive data from the API e.g. banking data. This could then be returned to the owner of the malicious website.
Fortunately, CORS offers a solution to this. By default, cookies cannot be sent in a cross-origin JavaScript request. To try to do so, without following the steps below, produces this JavaScript error:
‘Access-Control-Allow-Credentials’ header in the response is ’’ which must be ’true’ when the request’s credentials mode is ‘include’.
To include cookies, the server must return an Access-Control-Allow-Credentials
header with a value of true
.
For example, suppose you’re accessing a website https://my-banking-dashboard.com
. The following JavaScript code, running on the page, attempts a request to the origin https://api.mybank.com
:
fetch("https://api.mybank.com/summary", {
credentials: 'include'
});
The credentials: include
property tells the browser to include any cookies available for the api.mybank.com
domain.
In this case, we’re making a simple GET
request, without a pre-flight request. So the request might look like this:
Request headers
Origin: https://my-banking-dashboard.com
Cookie: Authorization=123abc;<other cookie 1>;<other cookie 2>
Here, the request includes the Cookie
header, with a cookie set by a previous request.
Now the server validates the cookie and returns a success response:
Response status code
200 OK
Response headers
Access-Control-Allow-Origin: https://my-banking-dashboard.com
Access-Control-Allow-Credentials: true
Response body
{"balance":"10000000", "currency": "GBP"}
There are 2 important requirements for the response:
-
the
Access-Control-Allow-Credentials
header must be set totrue
. If it’s missing, you’ll receive the JavaScript error shown above. -
the
Access-Control-Allow-Origin
header cannot be the wildcard*
any origin value. It must be set to a specific origin.
If the response meets these requirements, the browser accepts it and retrurns it to the JavaScript code.
Try this example in the interactive CORS simulator. Or see how credentials are sent with a pre-flighted request.
Setting cookies: to receive cookies via the Set-Cookie
response header, follow the same steps described above i.e. set the Access-Control-Allow-Credentials
and Access-Control-Allow-Origin
response headers appropriately.
9. Do pre-flights requests cause slowdown?
Since some cross-origin requests require an additional pre-flight request, it’s sensible to ask whether this could have a performance impact on a website.
The good news is that by default the browser caches the response to the pre-flight request for 5 seconds. This means that any additional pre-flighted requests made by JavaScript, within the time period, can use the cached response.
If you want to change the cache time, then return an Access-Control-Max-Age
header in the pre-flight response.
Here are some example values the header can take:
-
0
means no caching -
5
is the default value -
600
would be 10 minutes
To see a caching example in practice, check out the Interactive CORS Simulator.
10. What are some CORS best practices?
Even though the ideas behind CORS are simple, there are lots of implementation details and edge cases to consider.
Here are 3 best practices to keep in mind when implementing CORS:
-
Avoid a value of
*
forAccess-Control-Allow-Origin
CORS empowers the server to decide which origins browsers can send requests from. Be specific when configuring theAccess-Control-Allow-Origin
header. For example, if your website is hosted athttps://my-site.com
, then including that origin may be sufficient. -
Rely on server frameworks as much as possible Since there are so many different headers and edge cases to remember, if you try to implement CORS yourself, you’ll probably make a mistake. Instead, rely on well-used 3rd-party server frameworks to do the heavy lifting e.g. Spring Boot or AWS API Gateway, as described above.
-
Test your CORS logic in the browser Once you’ve setup CORS on the server, you’ll inevitably test that your website works as expected in the browser. It’s also worth testing the inverse, that a server request from an unexpected origin is blocked by the browser’s CORS policy. This can be as simple as running the
fetch
function from the JavaScript Console when viewing a website from an unrelated origin.
11. CORS header summary table
We’ve covered all 8 CORS request and response headers, which can all be conveniently identified by their Access-Control
prefix.
Request headers
Any required request headers are set automatically by the browser when you make a cross-domain JavaScript fetch
request.
Header name | Main or pre-flight request? | Purpose | Value |
---|---|---|---|
Access-Control-Request-Headers |
Pre-flight | Defines HTTP headers to be sent in the main request | Comma-separated list of header names |
Access-Control-Request-Method |
Pre-flight | Defines HTTP method to be used for the main request | Single request method |
Response headers
Header name | Main or pre-flight request? | Purpose | Value |
---|---|---|---|
Access-Control-Allow-Origin |
Both | Defines origin from which browser can make requests | * or explicit origin |
Access-Control-Allow-Methods |
Pre-flight | Defines possible request methods to use for main request | Comma-separated list of request methods |
Access-Control-Allow-Headers |
Pre-flight | Defines possible headers to send in main request | Comma-separated list of header names |
Access-Control-Expose-Headers |
Main | Defines headers for browser to expose to JavaScript | Comma-separated list of header names |
Access-Control-Allow-Credentials |
Both | Defines whether credentials can be included in the request | true (false when header omitted) |
Access-Control-Max-Age |
Pre-flight | Defines for how long the browser should cache the pre-flight response | Number of seconds (default 5) |
12. Final thoughts
You should now have a good understanding of why CORS exists, how it works, and how to implement it in many different use cases.
To fully understand these ideas, I recommend trying out the examples described above yourself. The easiest way to do this is to run through the Interactive CORS Simulator, which showcases many concepts from this article.