Logo
Back to Blog
Web Development August 8, 2026 9 min read

What Is CORS? Cross-Origin Resource Sharing Explained

O

OmniWebKit Team

Web Standards

Share:
Article Cover Image

Your fetch call fails with a wall of red text about origins and policies. The server is fine, the URL is right, and nothing you change in your code helps. The browser is doing this deliberately, and once you know why, the errors stop being mysterious.

What Is CORS, in One Paragraph

CORS is how a server tells the browser which other sites may read its responses.

Cross-Origin Resource Sharing is a set of HTTP headers. The server sends them; the browser enforces them.

By default a page cannot read data from a different origin. CORS is the mechanism for granting exceptions, one origin at a time.

Nothing about it happens on your server beyond sending a header. All the enforcement is in the browser.

To see which headers a given endpoint returns, run it through our CORS tester.

The Same-Origin Policy Underneath It All

Two URLs share an origin only when scheme, host and port all match.

URLSame origin as https://example.com/app?
https://example.com/otherYes — only the path differs
http://example.com/appNo — different scheme
https://api.example.com/appNo — different host
https://example.com:8443/appNo — different port

That table explains most local development pain. Your app on port 3000 and your API on port 8080 are different origins, so CORS applies on your own machine.

The Same-Origin Policy is the default; CORS is the opt-out. The policy came first by about fifteen years.

Why Does CORS Exist? A Concrete Example

Without it, any site you visit could read your logged-in data from any other site.

Picture your bank at bank.com, where you are signed in with a session cookie. You then open a link to a site you do not trust.

That site runs a fetch to bank.com/api/accounts. Your browser attaches your cookie automatically, because that is what cookies do.

The Same-Origin Policy is what stops the attacker reading the reply. Without it, one careless click would expose every authenticated account you hold.

Seen that way, CORS is not an obstacle. It is the mechanism that lets the browser relax a rule you very much want by default.

What Actually Happens on a Blocked Request

The response is discarded after it arrives, not before it is sent.

For a simple request the sequence is:

  1. Your code calls fetch.
  2. The browser sends the request, including an Origin header.
  3. The server replies.
  4. The browser checks for Access-Control-Allow-Origin.
  5. No match, so it throws the response away and reports an error.

Step three is the part people find surprising, and it has a real consequence. If that request deleted a record, the record is gone — you just cannot read the confirmation.

This is exactly why CSRF protection is a separate concern. CORS governs reading, not doing.

The Meaning of a Preflight Request

For anything beyond a plain request, the browser asks permission before sending.

It fires an OPTIONS request first, describing what it intends to do. Only a satisfactory answer lets the real request proceed.

Three things trigger it: a method other than GET, HEAD or POST; any non-safelisted header such as Authorization; or a JSON content type.

That third condition means nearly every modern API call is preflighted. We cover the mechanics in how preflight requests work.

What CORS Does Not Do

It is not a firewall, and treating it as one is a genuine risk.

  • It does not stop non-browser clients. curl, Postman and any server-side script ignore it completely.
  • It does not prevent the request. Side effects still happen.
  • It does not authenticate anyone. You still need real auth.
  • It does not stop CSRF. Different problem, different defence.

We say this because "our API is protected by CORS" comes up in review more often than it should. A restrictive CORS policy on an unauthenticated endpoint protects nothing.

Once you are ready to send real requests with auth, our API tester handles the full round trip.

Wrapping Up

CORS is the browser asking a server whether one site may read another site's response. The server answers with headers, and the browser obeys.

Remember the two things it is not: not a server-side protection, and not a defence against actions. It governs reading, in browsers, only.

Hitting a specific error? Start with the missing origin header, or look up any header in our complete CORS headers reference.

Frequently Asked Questions

Does CORS protect my server from attackers?

+
No, and assuming it does is a real security mistake. CORS is enforced by browsers only, so a script, a proxy, or anyone with curl ignores it entirely. Your API still needs authentication and rate limiting.

Why does the request reach my server if the browser blocks it?

+
Because the block happens on the response, not the request. For simple requests the browser sends it, gets the answer, then refuses to show your code the result. Any side effect on the server has already happened.

Is a different port really a different origin?

+
Yes, and so is a different scheme. An origin is scheme plus host plus port, so localhost:3000 and localhost:5173 are as distinct as two unrelated domains. That is why local development runs into CORS constantly.

Why can a script tag load from any domain but fetch cannot?

+
Because script, img and link tags can fetch cross-origin without letting the page read the contents. Fetch returns the actual bytes to your JavaScript, which is exactly what the Same-Origin Policy exists to prevent.

Do subdomains count as the same origin?

+
No. app.example.com and api.example.com are separate origins and need CORS between them. There is a legacy document.domain mechanism for related subdomains, but browsers are removing it and it never applied to fetch.

Does CORS apply to server-to-server requests?

+
Never. There is no browser in that path, so nothing enforces it. This is why a backend proxy is the standard fix when you cannot change a third-party API.

What is the difference between CORS and CSRF protection?

+
CORS controls who may read a response. CSRF protection controls who may trigger an action. A cross-origin POST can still change your data even when the attacker cannot read the reply, which is why you need both.

Why do some errors mention an opaque response?

+
That is what you get with mode set to no-cors. The request goes out, the response comes back sealed — status 0, empty body, no headers. It exists for caching in service workers, not for reading data.

Is CORS the reason my images fail to load in a canvas?

+
Yes. An image drawn from another origin taints the canvas so no script can read the pixels back. Set crossOrigin to anonymous and make sure the remote server sends the allow header.

Has CORS changed much recently?

+
The core model has been stable for years. What changes around it is cookie policy — SameSite defaults tightened considerably, which broke plenty of cross-site setups that had worked for a decade.

Tags

#CORS#Security#Web Standards#Fundamentals