Cross-Origin-Opener-Policy
Send `Cross-Origin-Opener-Policy: same-origin` to put your page in its own browsing context group, cutting `window.opener` references from cross-origin pages.
Correct for some sites and disruptive for others. Read what it breaks before deploying.
What it does
When a page opens or is opened by another window, the two keep a reference to each other through `window.opener`. Cross-origin, that reference is limited but not nothing — it permits navigation of the other window and contributes to the side channels that made Spectre exploitable from the web.
COOP severs it. With `same-origin`, your document goes into its own browsing context group: a cross-origin page that opened you gets `null` for `window.opener`, and you get `null` for anything you open cross-origin. Combined with COEP it produces a cross-origin isolated context, which is the precondition for `SharedArrayBuffer` and high-resolution timers.
The cost is concrete and lands on exactly the flow most sites have. OAuth and payment providers that open a popup and communicate back via `window.opener.postMessage` stop working under `same-origin`. `same-origin-allow-popups` exists for this: it isolates you from whoever opened you, while keeping the reference to popups you open yourself. That is usually the right first step.
There is a second reason to send it that has nothing to do with `SharedArrayBuffer`, and it is the one that applies to ordinary sites. A page opened via `target="_blank"` from somewhere else keeps a live handle on your window, and that handle is enough to navigate it — an attacker-controlled page can wait, then replace the tab behind it with a convincing copy of your login screen. `rel="noopener"` fixes that from the linking side, which is no help at all when the link is on someone else's site. COOP fixes it from yours, which is the only side you control.
What to send
Cross-Origin-Opener-Policy: same-origin-allow-popupsIt gives you the protection that matters — no cross-origin page keeps a handle on your window — while leaving popup-based OAuth and payment flows working. Move to `same-origin` only if you need full cross-origin isolation, and only after auditing every popup your application opens.
Directives and values
The default. The page can be placed in a shared browsing context group with cross-origin documents, and `window.opener` works as it always has.
Isolates the document from whoever opened it, but keeps references to popups it opens itself. The pragmatic value for sites with OAuth or payment popups.
Full isolation in both directions. Required for cross-origin isolation alongside COEP, and the value that breaks popup callbacks.
`Cross-Origin-Opener-Policy-Report-Only` reports what would be severed without severing it — the way to find out what breaks before it does.
Common mistakes
- Shipping same-origin with an OAuth popup flow. The popup completes, calls `window.opener.postMessage`, and finds `null`. The user sees a popup that closes and a login that never finishes. Use `same-origin-allow-popups`, or move the flow to a full-page redirect.
- Expecting COOP alone to enable SharedArrayBuffer. Cross-origin isolation needs COOP `same-origin` **and** COEP `require-corp` or `credentialless`. Either alone leaves `crossOriginIsolated` false and the API unavailable.
- Deploying without the report-only pass. The breakage is in flows that are exercised rarely — a partner SSO, a payment redirect, a support widget. `Cross-Origin-Opener-Policy-Report-Only` surfaces them without taking anything down.
- Setting it on an endpoint that is meant to be a popup. The header applies to the document being loaded. A callback page that needs to talk back to its opener should not carry a policy that severs the link.
Browser support
Supported in all current major browsers. Older clients ignore it, so it is additive rather than risky from a compatibility standpoint — the risk is entirely in what it intentionally severs.
Frequently asked questions
What does Cross-Origin-Opener-Policy do?
It controls whether your document shares a browsing context group with cross-origin pages. With `same-origin`, a cross-origin page that opened yours receives `null` from `window.opener`, which removes a class of cross-window attack and is a prerequisite for cross-origin isolation.
Does COOP break OAuth popups?
The `same-origin` value does, because the popup can no longer reach `window.opener` to post its result back. `same-origin-allow-popups` keeps that flow working while still isolating your page from whatever opened it, and is the right value for most sites.
What do I need for cross-origin isolation?
Both `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` (or `credentialless`). Only then does `crossOriginIsolated` become true and APIs such as `SharedArrayBuffer` and high-resolution timers become available.
How do I test COOP before enforcing it?
Send `Cross-Origin-Opener-Policy-Report-Only` with a reporting endpoint. Browsers report what the policy would have severed without actually severing it, which surfaces rarely-exercised popup flows before users hit them.
The free Security Headers Checker reads Cross-Origin-Opener-Policy from a live response and grades it alongside every other header on this reference — no account needed.
For the longer treatment, read Advanced HTTP Security Headers: A Deep Dive in the Learning Center.
Related headers
Requires every cross-origin resource to opt in. The second half of cross-origin isolation, and the expensive half.
Declares who may load your resources at all. Blocks side-channel reads that CORS does not cover.
Blocks framing to prevent clickjacking. Superseded by CSP frame-ancestors, but still worth sending.