Cross-Origin Resource Sharing (CORS) - HTTP | MDN

CORS errors are common in frontend development. A request is made, and the browser blocks it, displaying a message about the CORS policy. At first glance, it seems like a frontend problem.

In reality, it’s a backend configuration issue.

Understanding how CORS works helps clarify why the backend is responsible and how misconfigurations can affect both functionality and security.


What CORS Does

CORS (Cross-Origin Resource Sharing) is a browser security feature. It controls which origins are allowed to make requests to a server and read the responses.

Browsers block cross-origin requests by default. CORS headers are the server’s way of telling the browser that a request from another origin is permitted.

For example, if a frontend at (https://app.example.com) tries to call an API at (https://api.example.com)

the browser checks the server’s response for CORS headers. If those headers are missing or incorrect, the browser will not expose the response to the frontend code.

The request still reaches the server, but the browser will prevent the frontend from seeing the result.


Why It’s a Backend Concern

The browser enforces CORS, but the decision is made by the server. The frontend cannot influence whether the server allows a request from a particular origin. That decision comes entirely from how the backend sets response headers.

If a request is being blocked, it’s because the backend didn’t respond with the right headers. No amount of frontend changes can fix that.


Common Misconfigurations

1. Allowing All Origins with Credentials

This happens when the server responds with:

http
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

This combination is not allowed. When credentials like cookies are involved, the origin must be explicitly specified. Using * with credentials can lead to inconsistent behavior and potential security concerns.

2. Reflecting the Origin Without Validation

Some servers are configured to set the Access-Control-Allow-Origin header based on the request’s Origin header, without checking if that origin is trusted.

js
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);

Unless there’s validation against a known list of allowed origins, this approach allows any website to interact with the API as if it were trusted. That undermines the purpose of CORS.

3. Not Handling Preflight Requests

Browsers send a preflight request using the OPTIONS method before certain types of requests. If the server does not respond correctly to these preflight requests, the browser will block the actual request, even if the server would otherwise allow it.

This is often the reason developers see something work in tools like Postman, but not in the browser. Postman does not enforce CORS, but browsers do.


What the Backend Should Do

Use a Clear Origin Policy

Define a list of allowed origins and validate incoming requests against it. Only respond with Access-Control-Allow-Origin if the origin is trusted. Avoid using wildcards when credentials are involved.

Respond to Preflight Requests

Make sure the server handles OPTIONS requests with the appropriate headers:

  • Access-Control-Allow-Methods
  • Access-Control-Allow-Origin
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Credentials

Also ensure the server sends a valid status code in response, typically 200 or 204.

Understand What CORS Protects

CORS is not a form of authentication. It does not prevent malicious clients from calling your API directly. It only prevents browsers from allowing certain frontend JavaScript calls across origins.

Security must still be handled separately through proper authentication, authorization, and request validation.


TL;DR

CORS is often misunderstood because the errors appear in the browser, but it is not a browser bug or a frontend mistake. It is a policy defined and enforced by the server, and that’s where it must be configured correctly.

Taking the time to understand how CORS works leads to fewer development issues and avoids exposing your APIs to unnecessary risks.

If your backend serves data to other origins, CORS should be treated as part of your backend's access control model, not as an optional frontend workaround.