Browser security boundaries
Understand the origin boundary
Use scheme, host, and port to reason about which documents and requests can share browser authority.
The browser uses an origin as a major security boundary. An origin is the exact triple of scheme, host, and port. All three must match for two documents to share full browser authority.
That means https://app.flaviocopes.com and http://app.flaviocopes.com are different origins, because the scheme differs. https://app.flaviocopes.com and https://app.flaviocopes.com:8443 are different origins, because the port differs. The host is compared exactly, so flaviocopes.com and www.flaviocopes.com do not match either.
Sending is not the same as reading
The same-origin policy restricts one origin from reading another origin’s data. It does not stop every cross-origin request from being sent. This distinction is where most confusion starts.
// Runs on https://evil.example
// The request IS sent, and cookies for the target may ride along
fetch('https://api.flaviocopes.com/account', { credentials: 'include' })
.then(res => res.json()) // ← the browser blocks reading this response
.catch(err => console.log('read blocked:', err))
The fetch() above leaves the browser and hits your server. The browser only refuses to hand the response back to the calling script. An HTML form is even more permissive: it can POST to any origin and the request arrives at your server normally.
<!-- A plain form posts cross-origin with no restriction -->
<form action="https://api.flaviocopes.com/account/email" method="post">
<input name="email" value="[email protected]">
</form>
https://app.flaviocopes.com and https://api.flaviocopes.com belong to the same company but not the same origin. A browser may send a cross-origin form while refusing JavaScript access to its response.
Saying “the browser blocks cross-origin requests” hides this important difference. Design separately for sending, reading, cookies, navigation, and other browser-controlled behavior.
Classify five URLs by scheme, host, and port, then test one cross-origin fetch() and one HTML form submission. Record whether each request was sent and whether the initiating page could read the response.
Lesson completed