# Cross-Origin-Opener-Policy

> Learn how Cross-Origin-Opener-Policy (COOP) isolates your browsing context from cross-origin documents. Required for SharedArrayBuffer and enhanced security.

Source: https://howhttpworks.com/headers/cross-origin-opener-policy
Last reviewed: 2026-10-05

> **TL;DR:** `Cross-Origin-Opener-Policy: same-origin` separates your top-level document from incompatible popup/opener contexts. It can break OAuth and payment popup callbacks. Use it with COEP for cross-origin isolation; `same-origin-allow-popups` preserves only certain popup relationships.

## What is Cross-Origin-Opener-Policy?

COOP determines whether top-level documents share a browsing context group. A group switch severs their window references. This is different from CORS, which controls sharing fetched responses, and from X-Frame-Options, which controls framing. Both documents' origins and policies matter. [HTML defines the matching rules](https://html.spec.whatwg.org/multipage/browsers.html#cross-origin-opener-policies).

## Syntax

```http
Cross-Origin-Opener-Policy: same-origin
```

Return it on the document response. It is not an API access-control header.

## Value Guide

- `unsafe-none` is the default. It does not request isolation, but another document's policy can still force a group switch.
- `same-origin` shares a group only with same-origin documents that have a matching policy.
- `same-origin-allow-popups` matches same-origin documents with that same policy, and permits popups opened with `window.open()` to remain connected when the popup uses `unsafe-none`.
- `noopener-allow-popups` severs the incoming opener relationship, including from same-origin openers, while allowing the document to open `unsafe-none` popups.

These are behavioral rules, not guarantees of a particular OS process layout. Consult [MDN's navigation and window.open tables](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Opener-Policy#description) for combinations.

## Example

Illustrative document response header excerpt:

```http
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
```

Verify in the document:

```javascript
console.log(window.isSecureContext, window.crossOriginIsolated)
```

## Implementation

Inside the nginx server or location serving HTML:

```nginx
add_header Cross-Origin-Opener-Policy "same-origin" always;
```

Use [nginx's header directive](https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) and inspect the final response after proxies or middleware have run. Duplicate or overridden policy headers are harder to diagnose than a single policy owned by one layer.

For an existing Express app, register document middleware before the route serving HTML:

```javascript
app.use('/isolated', (_req, res, next) => {
  res.set({
    'Cross-Origin-Opener-Policy': 'same-origin',
    'Cross-Origin-Embedder-Policy': 'require-corp'
  })
  next()
})
app.get('/isolated', (_req, res) => {
  res.sendFile('isolated.html', { root: '/srv/app/public' })
})
```

Create `/srv/app/public/isolated.html` for this route. [Express supports header middleware and rooted file responses](https://expressjs.com/en/5x/api/response/#res.sendFile). Scope these headers to the documents that need isolation, then test their resources and popup flows.

## Operational Impact

For a popup flow, inspect the document response after every navigation, including the identity-provider page and callback. A group switch can make `window.opener` null and make the opener's retained window handle appear closed. [MDN documents severed window.open references](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#return_value).

Calling `window.opener.postMessage(...)` when `window.opener` is null throws; it does not silently deliver or silently succeed. Log the opener value on the callback page before investigating message handlers.

## COOP, COEP, and CORP Together

COOP controls window relationships. [COEP](https://howhttpworks.com/headers/cross-origin-embedder-policy) controls resource embedding requirements. [CORP](https://howhttpworks.com/headers/cross-origin-resource-policy) is one resource-side way to satisfy no-cors embedding requirements. A global CORP header is not a third mandatory switch for isolation; successful CORS loads can satisfy the resource checks instead.

## COOP and Cross-Origin Isolation

For a secure top-level document, use COOP `same-origin` with COEP `require-corp` or `credentialless`. The `cross-origin-isolated` permissions policy must also allow the capability. Check [crossOriginIsolated](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated) before selecting a SharedArrayBuffer path.

`same-origin-allow-popups` does not provide that isolation capability. It can preserve an OAuth popup using `unsafe-none`, but cannot override a restrictive policy sent by the provider. Test the actual provider and callback rather than assuming that changing the opener header repairs every flow. Redirect-based login avoids depending on a surviving popup opener reference.

## Related Headers

- [Cross-Origin-Embedder-Policy](https://howhttpworks.com/headers/cross-origin-embedder-policy)
- [Cross-Origin-Resource-Policy](https://howhttpworks.com/headers/cross-origin-resource-policy)
- [Permissions-Policy](https://howhttpworks.com/headers/permissions-policy)
