What Is CORS and How It Affects JavaScript Fetch
Cross-Origin Resource Sharing (CORS) is a vital browser security
mechanism that regulates how web applications interact with resources
hosted on different domains. This article breaks down the fundamentals
of CORS, explains the underlying Same-Origin Policy, details how CORS
directly impacts JavaScript fetch calls, and outlines the
standard ways to resolve cross-origin errors in modern web
development.
What is Cross-Origin Resource Sharing (CORS)?
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.
By default, web browsers enforce the Same-Origin Policy
(SOP). Under SOP, a web page can only make requests to the same
origin from which it was loaded. An origin consists of three parts: *
Protocol (e.g., http:// vs
https://) * Host/Domain (e.g.,
example.com vs api.example.com) *
Port (e.g., :80 vs :3000)
If any of these three components differ between the requesting site and the target server, the request is classified as cross-origin. CORS provides a secure way for servers to relax the Same-Origin Policy and selectively allow cross-origin access.
How CORS Affects
JavaScript fetch Calls
When you use the JavaScript fetch() API to retrieve data
from or send data to another origin, the browser automatically attaches
CORS-related HTTP headers to the request.
1. Browser-Enforced Blocking
CORS is enforced by the browser, not the server.
When a fetch() call is made to a different origin: 1. The
browser sends the request to the external server. 2. The server
processes the request and sends back a response. 3. The browser checks
the response headers (specifically
Access-Control-Allow-Origin). 4. If the appropriate headers
are missing or do not match the requesting origin, the browser blocks
the JavaScript execution context from accessing the response and throws
a TypeError: Failed to fetch along with a console
error.
2. Simple Requests vs. Preflight Requests
The browser handles fetch requests in one of two ways
based on the request’s characteristics:
- Simple Requests: Standard
GET,HEAD, or simplePOSTrequests with basic headers (likeContent-Type: text/plainorapplication/x-www-form-urlencoded) are sent directly. The browser inspects the response headers before passing the data to your JavaScript code. - Preflight Requests: If the
fetchrequest uses methods likePUT,DELETE, orPATCH, or includes custom headers (such asAuthorizationorContent-Type: application/json), the browser automatically sends an HTTPOPTIONSrequest first. This “preflight” asks the server for permission before sending the actual request. If the server approves theOPTIONSrequest, the realfetchcall is executed.
Essential CORS Headers
To allow cross-origin fetch calls, the receiving server
must respond with specific headers:
Access-Control-Allow-Origin: Specifies which origins can access the resource (e.g.,https://example.comor*for public access).Access-Control-Allow-Methods: Lists allowed HTTP methods (e.g.,GET, POST, PUT, DELETE, OPTIONS).Access-Control-Allow-Headers: Lists custom headers that can be sent in the actual request (e.g.,Content-Type, Authorization).Access-Control-Allow-Credentials: Indicates whether cookies, authorization headers, or TLS client certificates can be exposed to the frontend whencredentials: 'include'is set in thefetchoptions.
Handling CORS in Practice
- Configure the Server: The correct solution to a
CORS error is updating the backend server or API gateway configuration
to return the appropriate
Access-Control-Allow-*headers. - Use a Proxy in Development: If you cannot modify
the backend during development, route frontend
fetchcalls through a local development proxy (such as those provided by Vite, Next.js, or Webpack) so requests appear same-origin to the browser. - Understanding
mode: 'no-cors': Settingfetch(url, { mode: 'no-cors' })tells the browser not to use CORS rules, but the resulting response is marked as opaque. This means your JavaScript cannot read the response body, status code, or headers, making it useless for retrieving JSON or dynamic data.