Same-origin policy and CORS
Reason about origin boundaries, credentialed requests, preflight, and what CORS actually protects.

WHAT YOU WILL BE ABLE TO DO
Learning outcomes
- Explain same-origin policy and cors in plain language.
- Connect the behavior to the underlying browser or framework model.
- Implement the core pattern and reason through edge cases.
- Answer common follow-ups without relying on memorized phrases.
01Explain it simply
The same-origin policy is the browser's default rule that a document normally can only read data from resources that share its own scheme, host, and port. CORS is a controlled way for a server to opt into letting specific other origins read a response that the same-origin policy would otherwise block.
One-line definition: Reason about origin boundaries, credentialed requests, preflight, and what CORS actually protects.
02Mental model
A request can usually still be sent cross-origin; what CORS actually gates is whether the requesting page's JavaScript is allowed to read the response. A 'simple' request is sent and answered before the browser decides whether to expose it to script, while a request with custom headers, certain methods, or a non-simple content type triggers a preflight OPTIONS check first.
03Step by step
- Identify whether the request is same-origin or cross-origin by scheme, host, and port.
- Determine if the request qualifies as simple or requires a preflight.
- Have the server return Access-Control-Allow-Origin (and Allow-Credentials when needed) for the exact caller origin.
- Include Access-Control-Allow-Methods/Headers for methods or headers a preflight introduces.
- Never reflect an arbitrary Origin back when Allow-Credentials is true.
04Working example
// Preflight request the browser sends automaticallyOPTIONS /api/orders HTTP/1.1Origin: https://app.example.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: content-type
// Required response for the browser to allow the real requestHTTP/1.1 204 No ContentAccess-Control-Allow-Origin: https://app.example.comAccess-Control-Allow-Methods: PUTAccess-Control-Allow-Headers: content-typeThe browser sends the preflight before the real PUT request because a custom header (content-type: application/json) makes it non-simple. Only an exact matching Allow-Origin — not a wildcard, since credentials require an explicit origin — lets the follow-up request's response reach the page's script.
05Where it is used
- Public APIs consumed from a different frontend origin
- Third-party widgets embedded across sites
- Separating an API domain from an app domain
- Local development against a remote backend
06Common mistakes
- Using Access-Control-Allow-Origin: * together with credentialed requests, which browsers reject
- Believing CORS stops a server from receiving a cross-origin request at all
- Reflecting the request's Origin header unconditionally instead of validating an allowlist
- Assuming a successful curl request means the browser will expose the response to script
07Interview answer
Separate 'was the request sent' from 'can the page's script read the response' — that distinction is what CORS actually governs, and it's the single most common confusion interviewers probe.
If a cross-origin POST reaches the server and even changes data, but the browser console shows a CORS error, did the attacker's page succeed?
It can still succeed at causing the side effect — CORS only blocks the response from being readable by the calling script, not the request from being sent and acted on server-side; that's why CSRF defenses are separate from CORS.
DDConcept deep dives
Deep dive 1
Sending and reading are separate permissions
A browser will often still send a cross-origin request; what the same-origin policy and CORS actually gate is whether the requesting page's script may read the response. This is why a request can succeed server-side and still appear to 'fail' in the browser console — the failure is a read restriction, not a delivery restriction.
- A malicious site can often still cause a side effect even when CORS blocks reading the result.
- CSRF defenses exist precisely because request delivery isn't blocked by CORS.
- Origin comparison uses scheme, host, and port together — any difference is a different origin.
Deep dive 2
Preflight is the browser asking permission first
For requests the browser considers non-simple — custom headers, certain methods, JSON bodies — it sends an OPTIONS preflight and inspects the Allow-Methods/Headers/Origin response before sending the real request. A server that doesn't answer the preflight correctly blocks the follow-up request from ever being sent by the browser, not just from being read.
- Simple requests skip preflight and are sent immediately.
- Preflight responses are typically cached by the browser for a duration the server can control.
- A missing or wrong preflight response blocks the real request entirely.
Deep dive 3
Credentialed access requires an explicit origin
When a request carries cookies or other credentials, the wildcard Access-Control-Allow-Origin: * is disallowed by browsers — the server must name the exact origin. This forces a deliberate allowlist rather than an accidental blanket exposure of authenticated data to any origin that asks.
- Validate the incoming Origin header against a known list before echoing it back.
- Access-Control-Allow-Credentials: true must pair with an exact Allow-Origin, never a wildcard.
- Cookies also need appropriate SameSite settings independent of CORS configuration.
QAInterview questions and model answers
Attempt each answer aloud before opening it. The model answer shows the depth and precision expected in an interview; it is not a script to memorize.
Intermediate · Conceptual · 1 min · Question 1What does the same-origin policy actually restrict?Open model answer
Model answer
It restricts a document's script from reading data from a different origin — a different scheme, host, or port — by default. It does not by itself prevent a request from being sent; many cross-origin requests still leave the browser and reach the server.
Open question page →Intermediate · Conceptual · 1 min · Question 2What triggers a CORS preflight request?Open model answer
Model answer
A request becomes non-simple, and therefore preflighted with OPTIONS, when it uses a method beyond GET/HEAD/POST, includes custom headers, or uses a content type such as application/json. The browser confirms permission before sending the real request.
Open question page →Intermediate · Conceptual · 1 min · Question 3What does Access-Control-Allow-Credentials require?Open model answer
Model answer
When a request includes credentials such as cookies, the server must return an exact matching Access-Control-Allow-Origin rather than a wildcard, plus Access-Control-Allow-Credentials: true, or the browser withholds the response from script.
Open question page →Intermediate · Conceptual · 1 min · Question 4Does CORS protect a server from receiving malicious cross-origin requests?Open model answer
Model answer
No. CORS is enforced by the browser on the response side to protect users' data from being read by untrusted scripts. A server must independently authenticate and authorize every request regardless of CORS headers.
Open question page →Intermediate · Conceptual · 1 min · Question 5Why is reflecting the Origin header back as Allow-Origin risky?Open model answer
Model answer
It effectively grants every origin read access to the response, which defeats the purpose of the policy. A safe implementation validates the incoming Origin against an explicit allowlist before echoing it back.
Open question page →Intermediate · Conceptual · 1 min · Question 6How does JSONP relate to the same-origin policy?Open model answer
Model answer
JSONP worked around the restriction by loading a script tag, which isn't subject to the same read restriction, and executing a callback with the data. It has known injection risks and has been superseded by CORS for legitimate cross-origin data access.
Open question page →Beginner · Conceptual · 1 min · Question 7Does changing only the port count as a different origin?Open model answer
Model answer
Yes. Origin is defined by scheme, host, and port together, so http://example.com:3000 and http://example.com:4000 are different origins even though the host is identical.
Open question page →Advanced · Conceptual · 1 min · Question 8What is the purpose of the Vary: Origin response header alongside CORS?Open model answer
Model answer
It tells caches that the response body or headers differ depending on the request's Origin, preventing a shared cache from serving one origin's CORS-approved response to a different, unapproved origin.
Open question page →Advanced · Conceptual · 1 min · Question 9Can a cross-origin iframe read its parent page's DOM?Open model answer
Model answer
Not by default. The same-origin policy blocks that access unless both frames share the exact same origin, or they opt into a narrower communication channel such as postMessage.
Open question page →Intermediate · Conceptual · 1 min · Question 10What is a CORS-safelisted response header?Open model answer
Model answer
It is one of a small set of headers, such as Content-Type within certain values, that JavaScript can read from a cross-origin response without the server needing to list it in Access-Control-Expose-Headers.
Open question page →SCScenario questions
Scenario 1
An internal admin API needs to be called from a separate marketing site during a migration, using the user's existing session cookie.
- Confirm the exact origins that legitimately need access.
- Configure the API to return a specific Allow-Origin per validated request, never a wildcard, since credentials are involved.
- Set Allow-Credentials and ensure the client fetch uses credentials: 'include'.
- Keep SameSite and CSRF protections in place regardless of CORS configuration.
Reveal worked answer
I would maintain a small explicit allowlist of trusted origins server-side, echo back only a matching one, and enable Allow-Credentials for the cookie to be sent and read. CORS only controls whether the marketing site's script can read the response — I'd still need CSRF protections because the request itself can be sent by any origin regardless of CORS.