Storage and browser security
The same-origin policy
Understand the browser boundary that prevents one origin from freely reading another origin’s protected data.
The same-origin policy stops script from one origin from reading protected data that belongs to another origin.
Here’s why it exists. You’re signed in to your bank. In another tab you open evil.example. That page runs JavaScript, and that JavaScript can send a request to your bank. The browser may even attach your bank cookies to it. If the malicious page could then read the response, it would have your account data.
The same-origin policy is the rule that says: no, you can’t read that. The request may go out. The response comes back. But the script on evil.example never gets to look at it.
The read boundary is the whole point.
What the policy allows
People often summarize it as “cross-origin requests are blocked”. That’s wrong, and the wrong mental model makes CORS errors harder to understand. Browsers allow plenty of cross-origin actions:
- an
<img>can display an image from another origin - a
<form>can submit to another origin - a page can link to or embed another origin in an
iframe fetch()can send many requests even when script can’t read the response
What’s blocked is reading: the response body of a cross-origin fetch(), the DOM of a cross-origin iframe, another origin’s storage.
The controlled exceptions
Legitimate apps need to cross the line sometimes, so the browser gives you two doors with locks on them.
CORS headers let a server say “this origin may read my responses”. The server decides, not the page. We’ll go deep on this in the next lesson.
window.postMessage() lets two windows from different origins exchange messages. The sender should pass a specific target origin, and the receiver must check event.origin before trusting the data.
See it yourself
Open the Console on any site and fetch an API on a different origin:
fetch('https://api.github.com/users/flaviocopes')
Then compare two places. The Network panel shows whether the request was sent and what came back. The Console shows whether your script was allowed to use it. GitHub’s API sends CORS headers, so this one works. Try a site that doesn’t, and you’ll see a 200 in Network next to a CORS error in the Console.
That split, network success next to a browser access decision, is the thing to remember. And when you hit it on your own API, don’t “fix” it by reflecting every origin or turning checks off. Configure the server to allow only the origins, methods, and credentials your app needs.
Lesson completed