DEV Community

Cover image for Understanding CORS: Why Your API Request Failed
Arnav Sharma
Arnav Sharma

Posted on

Understanding CORS: Why Your API Request Failed

If you’ve built a frontend that talks to an API, chances are you’ve seen this error in your console:

Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000' 
has been blocked by CORS policy.
Enter fullscreen mode Exit fullscreen mode

At first glance, it feels random. Your API is up, your code looks fine… so why does the browser stop you?

The answer is CORS (Cross-Origin Resource Sharing) — one of those things that sounds complicated, but once you “get it,” debugging becomes way easier.

Let’s break it down step by step.


What is CORS, really?


CORS is a security feature in browsers. It basically says:

“A website should not be able to make requests to another site unless the other site explicitly says it’s okay.”

Example:

  • Your frontend runs at http://localhost:3000
  • Your backend API is at https://api.example.com

These are different origins (different host/port/protocol), so the browser treats the request as cross-origin.

And here’s the key: without CORS, any malicious website could secretly call APIs on your behalf (like your bank), and steal data.

So when your browser blocks that request, it’s not being mean — it’s protecting you.


How does CORS actually work?


Here’s the flow whenever you hit an API from another origin:

  1. The Browser Adds an Origin Header Example:
   Origin: http://localhost:3000
Enter fullscreen mode Exit fullscreen mode
  1. The Server Decides if It’s Allowed It must respond with something like:
   Access-Control-Allow-Origin: http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

If it matches, the browser lets the request go through. If not → CORS error.

  1. Preflight Requests (the “double request” thing you see) For some requests (PUT, DELETE, custom headers, etc.), the browser first sends an OPTIONS request (aka preflight). The server must reply with allowed methods and headers:
   Access-Control-Allow-Methods: GET, POST, PUT  
   Access-Control-Allow-Headers: Content-Type, Authorization  
Enter fullscreen mode Exit fullscreen mode

If anything’s missing, your actual request never gets sent.


Why your request failed (common reasons)

  1. No CORS headers at all
    → The server just didn’t set them.

  2. Wrong origin allowed
    → You’re on http://localhost:3000, but the server only allows https://myapp.com.

  3. Preflight not handled
    → The server ignores the OPTIONS request, so the browser stops right there.

  4. Credentials issue
    → You’re sending cookies/tokens, but the server didn’t set

   Access-Control-Allow-Credentials: true
Enter fullscreen mode Exit fullscreen mode

How to fix CORS issues

1. Set CORS headers on the server

In Node.js + Express:

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "http://localhost:3000");
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
  res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
  next();
});
Enter fullscreen mode Exit fullscreen mode

(Pro tip: just use the cors package, it saves you headaches.)


2. Use * in dev (but not in prod)

Access-Control-Allow-Origin: *
Enter fullscreen mode Exit fullscreen mode

Great for local testing. Terrible for production. Never expose private APIs this way.


3. Enable credentials if needed

res.header("Access-Control-Allow-Credentials", "true");
Enter fullscreen mode Exit fullscreen mode

And in frontend:

fetch(url, { credentials: "include" });
Enter fullscreen mode Exit fullscreen mode

4. Use a proxy during development

If you can’t change the backend (e.g., third-party APIs), use a proxy (Vite/CRA/Webpack dev server) so the request looks like it comes from the same origin.


Best Practices

  • Whitelist only the domains you trust.
  • Always handle OPTIONS requests properly.
  • Remember: CORS exists to protect users, not annoy developers (even though it feels that way sometimes).

Wrapping up

CORS errors are annoying, but they’re also a sign your browser is doing its job.

The trick is to remember:

  • The server decides who can call it.
  • The browser enforces that rule.

So next time you see the dreaded “blocked by CORS policy”, don’t panic. Check the headers, check the origin, and you’ll know exactly what’s wrong.

Top comments (0)