Same-Origin Policy and JavaScript Network Requests
The Same-Origin Policy (SOP) is a foundational web security model
that restricts how a document or script loaded by one origin can
interact with a resource from another origin. In JavaScript, this policy
dictates whether network requests initiated by APIs such as
fetch() or XMLHttpRequest can access and read
the responses returned by external servers. This article explains what
constitutes an origin, how SOP restricts cross-origin network
operations, and the standard mechanisms used to safely bypass these
restrictions.
What Defines an Origin?
An origin is defined by the combination of three components: 1.
Protocol (Scheme): e.g., http://
vs. https:// 2. Host (Domain): e.g.,
example.com vs. api.example.com 3.
Port: e.g., :80, :443, or
:3000
Two URLs share the same origin only if all three components match
exactly. For example, https://example.com/page1 and
https://example.com/page2 have the same origin, whereas
http://example.com and https://example.com do
not.
How SOP Governs JavaScript Network Requests
The primary purpose of SOP in JavaScript is to prevent malicious scripts on one site from reading sensitive data from another site without authorization. The policy applies specific rules to network interactions:
- Sending vs. Reading Responses: SOP does not always block a browser from sending a request across origins, but it strictly forbids JavaScript from reading the response unless explicit permission is granted by the receiving server.
- APIs Governed: APIs that allow programmatic reading
of network data—specifically
fetch()andXMLHttpRequest(XHR)—are strictly bound by SOP. If a script onhttps://site-a.comissues afetchrequest tohttps://site-b.com/data.json, the browser will send the request, but it will block JavaScript from accessing the response body and headers if cross-origin permissions are missing. - Resource Embedding vs. Programmatic Access: The
browser allows cross-origin embedding for certain HTML elements (such as
<img>,<script>,<link>, and<iframe>), but JavaScript cannot inspect the internal raw data of these embedded resources due to SOP.
Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is the standard mechanism that allows servers to selectively relax SOP restrictions for JavaScript requests. When a JavaScript request is made to a different origin, the browser and server communicate using HTTP headers:
- Simple Requests: For basic
GET,HEAD, or certainPOSTrequests with standard headers, the browser sends the request immediately with anOriginheader. The server responds withAccess-Control-Allow-Origin: <origin>. If the returned origin matches the requester or is*, JavaScript is permitted to read the response. - Preflight Requests: For requests modifying data
(
PUT,DELETE, or custom headers), the browser first sends an automatedOPTIONSrequest (a preflight). The server must approve the method, headers, and origin before the actual JavaScript request is executed. - Credentials: By default, cross-origin JavaScript
requests omit cookies and authorization headers. To include them, the
client must set
credentials: 'include'infetch(), and the server must respond withAccess-Control-Allow-Credentials: truealongside a specific origin (wildcards are rejected).
Other Mechanisms Interacting with SOP
- WebSockets: WebSockets are not strictly governed by
SOP. They use an initial HTTP handshake containing an
Originheader, leaving it up to the server to accept or reject the connection. - Window Messaging (
window.postMessage): When cross-origin communication is required between different windows or iframes, JavaScript can usepostMessage()to safely exchange data across origins without triggering network-level SOP blocks.