// Fetch the weather conditions in Kansas City, Missouri
Access to fetch at 'https://www.metaweather.com/api/location/2430683/'
from origin 'http://localhost:4000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled.
This is one tool in your browser's toolbox to keep your private information safe from theft by malicious actors. Y'see, the internet can be a wild place. Sometimes banditos ride into town, looking to steal personal data from the friendly townsfolk of these parts.
These internet banditos try to take advantage of the fact that you may still be logged into another website, to try to steal information. If you have
Conceptually, you want to use three access control headers in your server's response to permit/deny your requests.
Access-Control-Allow-Methods: POST, GET, OPTIONS
I'll briefly expand on these headers below, but you can read more about them here:
- Access-Control-Allow-Origin can be
null, an origin, or
*meaning all origins. Notice that you cannot permit a list of origins. Instead, you should check to see if the request's origin is in the list and, if it is, set the value to that origin, otherwise use
- Access-Control-Allow-Methods is a comma separated list of HTTP methods the server permits.
- Access-Control-Allow-Headers is a comma separated list of headers that can be included in the request. If you use a custom authentication header, it should be included here.
CORS policies only affect requests coming from browsers. You can setup another server to make the request on your behalf, and then have your
fetch request talk to that server instead. This is called a proxy. Your proxy should probably run in the same origin as your client app, or have its own CORS policy in place.
You can easily build a proxy in express, or you may already be hosting your client-side app from a web server that can act as your proxy. Either way, this is a step you only have to do once. You can reuse the same proxy for any number of APIs.
Okay I'm going to let it slide but just so you know, that wasn't actually a question.
It is a good idea to put your CORS configurations into your
.env or environment-specific configuration files. If you have separate environments for development/staging/production, it makes sense for them to have different CORS configurations. Your development server can just
Access-Control-Allow-Origin: * for simplicity, your staging servers can permit staging origins, and your production servers should only permit production origins. You shouldn't (and likely won't be allowed to) permit sharing with your development environment in Production.
If you don't have a development instance of your server, and your local environment must connect to the production server itself, you still have a few options. You can setup a proxy, as discussed earlier. If you're using
webpack-dev-server to run your local development environment, it has a proxy config option.
Access-Control-* headers in the response. For that to work, the request MUST reach the server so that the headers can be sent back!
This means that CORS policies won't protect your API from side effects of those requests. CORS alone won't protect your data from a request to delete your account, where the damage might be done even though the response message has been blocked by the browser. To safeguard against these kinds of vulnerabilities, any endpoints that "do something" besides just return data should be protected by CSRF tokens and/or via authentication beyond a mere session cookie.
If your server uses session cookies, you shouldn't allow sharing. Unless it's with a friend who would never abuse your trust and whose website is secure enough that it won't be hijacked. You also should not allow cross-origin requests if your API is authenticated using a private developer's Secret Token. If you did, then inevitably some developer will try to use it client-side. If they do that, and any one of their users checks out their network traffic, the users could steal the secret token and impersonate the developer.
CORS policies are enforced by all modern web browsers, regardless of what flavor of web client you use. CORS policies won't affect requests from non-XHR sources, such as
<form> actions. CORS won't apply to
<script> tags unless you set the crossorigin attribute.
This is one of those moments where the suggested solution in the error message is rarely ever the course of action you should actually take.
no-cors suppresses the error message, but it doesn't change the situation; the request still gets sent and you still can't read the response. Perhaps you want to send a message but you don't care whether or not the message was received or accepted. That's not usually the case.
I hope this has been a helpful primer on CORS policy errors. If you have questions or just want to chat, you can reach me @MrLeebo.