Skip to Content
Course content

166: Understanding Same-Origin Policy and CORS

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I can almost guarantee that at some point in your career, you're going to run into a console error that looks something like this: Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy. It's one of the most frustrating moments for a frontend developer because your code looks perfect, the server is running, and yet the browser is just refusing to let the data through.

Let's look at a piece of code that triggers this. Imagine you're building a weather dashboard and you're trying to pull data from a separate API server.

async function getWeather() {
  try {
    const response = await fetch('https://weather-api.internal.com/v1/forecast');
    const data = await response.json();
    console.log(data);
  } catch (err) {
    console.error('Fetch failed:', err);
  }
}

getWeather();

If you run this from your local dev environment, it will fail. You'll see that "CORS policy" error in the DevTools console, and your catch block will trigger. The weird part? If you paste that same URL directly into your browser's address bar, it works perfectly. You'll see the JSON right there on the screen. This discrepancy is where most people get confused.

The Wall: Same-Origin Policy

The reason this happens is the Same-Origin Policy (SOP). This is a fundamental security feature built into every modern browser. Its job is to prevent a malicious website from making requests to another site where you might be logged in (like your bank) and stealing your data using your active session cookies.

A "Origin" is defined by three things: Protocol (http vs https), Domain (localhost vs example.com), and Port (3000 vs 80). If any of these three differ between the site hosting the JS and the server you're calling, the browser considers it a "Cross-Origin" request. By default, the browser lets you send the request, but it blocks the JS from reading the response unless the server explicitly says it's okay.

The Key: Access-Control-Allow-Origin

To fix this, we use CORS (Cross-Origin Resource Sharing). CORS isn't a "JavaScript fix"—it's a server-side configuration. You cannot bypass CORS by writing clever JavaScript on the frontend; that would defeat the whole purpose of the security policy.

The server needs to respond with a specific HTTP header that tells the browser, "I trust this origin, go ahead and let them see the data." The most common header is Access-Control-Allow-Origin.

If you have control over the server (for example, a Node/Express backend), you would fix it like this:

const express = require('express');
const app = express();

// This allows ANY site to access your API. Great for public APIs, 
// but dangerous for private data.
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*'); 
  next();
});

app.get('/v1/forecast', (req, res) => {
  res.json({ temp: 72, condition: 'Sunny' });
});

app.listen(3000);

By adding res.setHeader('Access-Control-Allow-Origin', '*'), the server tells the browser that any origin (the * wildcard) is allowed. If you wanted to be more secure, you'd replace the * with your actual domain, like http://localhost:3000.

The "Pre-flight" Request

You might notice something strange in your Network tab: a request with the method OPTIONS that happens right before your actual GET or POST. This is called a Pre-flight request.

The browser does this when the request is "complex"—for example, if you're sending JSON data or using a custom header like Authorization. The browser essentially asks the server: "Hey, I'm about to send a POST request with a JSON body; are you cool with that?" If the server doesn't respond correctly to the OPTIONS request, the browser will never even attempt the real request.

I've seen developers spend hours debugging their POST logic only to realize the server wasn't configured to handle OPTIONS requests. Always check the Network tab first to see if the pre-flight is the part that's failing.




📋 Practical Task

Fixing the Cross-Origin Header in a Mock Server

You are given a mock Node.js server script that is currently blocking requests from your frontend. Your task is to modify the server middleware to allow requests specifically from http://localhost:5173 (a common Vite port) while rejecting everything else.

// server.js
const express = require('express');
const app = express();

// TASK: Modify this middleware to allow only http://localhost:5173
app.use((req, res, next) => {
  // Currently, there is no CORS header here, causing the browser to block requests.
  // Add the necessary header here.
  
  next();
});

app.get('/api/user', (req, res) => {
  res.json({ username: 'DevMentor', status: 'Online' });
});

app.listen(3000, () => console.log('Server running on port 3000'));

Requirements:

  • Do not use the * wildcard; restrict access to the specific origin mentioned.
  • Ensure the header is set before next() is called.
  • Verify that you are using the correct header name: Access-Control-Allow-Origin.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.