Articles

What Is CORS? Cross-Origin Requests, Explained

CORS lets a server opt in to cross-origin browser requests, relaxing the same-origin policy in a controlled way. Why it exists and how to fix CORS errors.

Takina Takina · · 4 min read
A connected globe network

CORS — Cross-Origin Resource Sharing — is a browser security mechanism that controls which cross-origin HTTP requests a web page is allowed to make. If you’ve ever seen Access to fetch at '…' from origin '…' has been blocked by CORS policy in your browser console, you’ve hit it. The fix is always on the server side.

Why the same-origin policy exists

Browsers enforce a same-origin policy (SOP): JavaScript running on https://example.com can freely fetch resources from https://example.com, but not from https://api.other.com. Two URLs share an origin only if their scheme, hostname, and port all match exactly.

This protection exists to prevent a malicious or compromised page from silently making authenticated requests to another site using your stored cookies or credentials. Without the SOP, visiting evil.com could trigger a JavaScript fetch to yourbank.com/transfer with your session cookie attached — and the bank would have no way to tell the difference.

CORS is the controlled exception to that rule. It lets a server advertise “I’m okay receiving requests from these other origins,” and the browser enforces those permissions.

How CORS works

Every cross-origin request the browser makes includes an Origin header naming the page’s origin:

Origin: https://myapp.com

The server’s response then includes (or omits) one or more Access-Control-Allow-* headers. The browser reads those headers and decides whether to expose the response to the JavaScript that made the request.

The key response headers:

  • Access-Control-Allow-Origin — which origin(s) may read the response. Can be a specific origin (https://myapp.com) or a wildcard (* — but wildcards can’t be used with credentials).
  • Access-Control-Allow-Methods — which HTTP methods are permitted (GET, POST, DELETE, etc.).
  • Access-Control-Allow-Headers — which request headers the client is allowed to send.
  • Access-Control-Allow-Credentials — whether cookies and HTTP auth may be included (true or omitted).
  • Access-Control-Max-Age — how long (in seconds) the browser may cache the preflight result.

Simple requests and preflight

Not every cross-origin request triggers a preflight. A simple request — a GET or POST with only safe headers and a content type of text/plain, multipart/form-data, or application/x-www-form-urlencoded — is sent directly. The browser checks the response headers afterward and either exposes the result to JavaScript or blocks it.

For anything else — a DELETE, a PUT, a request with Content-Type: application/json, or a custom header — the browser first sends a preflight request using the OPTIONS method:

OPTIONS /api/data HTTP/1.1
Origin: https://myapp.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Content-Type, Authorization

The server must respond to the preflight with the appropriate Access-Control-Allow-* headers and a 2xx status. Only if that check passes does the browser send the real request. If your REST API returns 404 or 405 for OPTIONS, preflight will fail and the real request will never be sent.

Credentialed requests

By default, cross-origin requests do not include cookies or HTTP authentication. To include credentials, the client must set credentials: 'include' in the fetch call, and the server must respond with both Access-Control-Allow-Credentials: true and an explicit origin (not *) in Access-Control-Allow-Origin. If either side omits its half of that handshake, the browser blocks the response.

The fix is always on the server

A CORS error is the browser correctly enforcing a server’s access policy — or a server failing to declare one. The solution is to configure the server to return the right Access-Control-Allow-* headers. You should not:

  • Disable CORS checks in your browser for development (it defeats the protection and hides real issues).
  • Use a browser extension to inject headers in production.
  • Route requests through a proxy just to avoid configuring CORS properly.

Most frameworks and runtimes have CORS middleware. Configure it with the specific origins your front end lives on, the methods you actually expose, and the headers your clients send. Wildcarding everything (*) is convenient in development but too permissive in production, especially once credentials are involved.

Understanding what an API is and how REST APIs work is useful context here — CORS is primarily a concern when browser-based JavaScript calls external API endpoints. And since CORS errors are meaningless without HTTPS, you’ll want that sorted first. If your API returns JWTs, bear in mind that the Authorization header triggers a preflight — your server needs to declare it in Access-Control-Allow-Headers.

The takeaway

The same-origin policy protects users from cross-site request forgery; CORS is the server’s mechanism for relaxing it in a controlled, explicit way. The browser enforces whatever the server declares. To fix a CORS error: add the correct Access-Control-Allow-* headers on the server, handle OPTIONS preflight requests, and if you need cookies or auth headers, pair Access-Control-Allow-Credentials: true with an explicit origin — never a wildcard. The browser is doing its job; configure the server to match your intent.

JavaScript developers often encounter CORS when their front end — written in JavaScript — calls an API on a different domain. It’s one of those errors that seems mysterious until you understand the same-origin policy, after which it becomes entirely predictable.

Chisato Chisato · · 3 min read

What Is XSS? Cross-Site Scripting Explained

Cross-site scripting (XSS) injects malicious scripts into pages other users view. How stored, reflected, and DOM-based XSS work, and how to prevent them.

#Security #Web Development #JavaScript
Chisato Chisato · · 4 min read

What Is a Content Security Policy (CSP)?

A Content Security Policy is an HTTP header that restricts what scripts and resources a page can load, blocking most XSS attacks by default.

#Security #Web Development #JavaScript
Takina Takina · · 4 min read

TypeScript Abstract Classes, Explained

Abstract classes in TypeScript define shared implementation plus methods subclasses must fill in. How they differ from interfaces and when to reach for them.

#TypeScript #JavaScript #Web Development