This post is intended to give you a swift kick from behind into a pool of CORS, without taking all day to do so, and without digging into any specific technologies. With that said, let’s learn to swim.
What is CORS?
From Mozilla: “Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.”
A key point here is that this is all about browsers. It may help to think of a web browser, not as part of your application, but as a go-between for your web and server-side applications. This is why a browser can block traffic to your application, and why a response blocked by a browser doesn’t mean anything is wrong with your web application or your web API. This may give you a confusing failure in your web application because you won’t actually get a failed request from the web API; you will get a blocked response. You may verify that your web application’s HTTP requests have the proper CORS headers and that your server-side application is configured to respond with the appropriate CORS headers to your web application. But in general, you should not bother looking for errors or exceptions while debugging CORS issues.
CORS, huh, yeah. What is it good for?
CORS may seem as though it’s always getting in your way, but this policy is to protect the users of a web application from exploits (a topic we will not explore further). Your goal is to work safely within the constraints of CORS. To do this, the web browser will effectively ask the web API (in our example) if the web application is trusted by the web API. If it is trusted, it can share resources. If it’s not, then it can’t. Now, what do you need to do to get this working?
Request & Response Headers
If your web API receives a request that contains the “Origin” header, and that header is included in the “allowed” origins by your API, then the appropriate CORS headers must be added to the HTTP response. Those headers may be:
- Access-Control-Allow-Credentials: “true” if credentials are allowed cross-origin (otherwise this header is omitted).
- Access-Control-Allow-Origin: * (all origins allowed), null (may be used to indicate requests coming from a file on the user’s computer), or the client’s actual origin value (e.g., http://localhost:4200). This header is required on all CORS responses.
- Access-Control-Expose-Headers: can be used to expose headers to client applications.
All you need to include with an HTTP request from the web application is the “Origin” header to let the API know from whence the request came. The browser or web framework you use will likely do this for you.
While you only need CORS headers for use in web browsers, this does not mean you need a browser to test and validate CORS responses from an API. You can use Postman, cURL, or anything else to test the API. All you have to do is add the “Origin” header as described above and see what happens. Or, you can check out this handy online tool.
A Quick Word on Preflight Requests
A “preflight” request, in short, is a request that happens prior to another request. You may see “OPTIONS” requests in the network tab of your browser, followed by the “POST”, “PATCH”, or whatever request you actually intended to make. In these requests, the browser is quite literally asking the API for the “options” it has for making subsequent calls. This will probably happen automatically without you ever knowing, until it fails due to misconfigured CORS responses.
OPTIONS requests will include the following headers:
- Origin (as discussed above)
- Access-Control-Request-Headers (what headers the client would like to send)
- Access-Control-Request-Method (what method would the client like to use for the actual request)
OPTIONS responses may include more headers than an actual CORS request:
- Access-Control-Allow-Headers (what headers the client is allowed to send)
- Access-Control-Allow-Methods (what methods the client is allowed to use)
- Access-Control-Allow-Origin (as described above)
- Access-Control-Max-Age (how long should the browser cache the response)
These requests and responses can also be tested outside the browser simply by sending an OPTIONS request to the API with the appropriate headers.
Regardless of the technology you’re using, be it a .NET Web API hosted in Azure, an API Gateway in AWS, or a locally run Angular web app using the Angular CLI, you will need to learn how to configure CORS. A little basic knowledge of what you need and why you need it can go a long way. For a much more thorough explanation, I recommend checking out the resources below.