Cross-Origin Opener Policy
COOP same-origin and same-origin-allow-popups: sever window.opener, process isolation, and OAuth popups.
- browser
- coop
- coep
- window-opener
- security
Cross-Origin Opener Policy (COOP) lets a document declare that it should not share a browsing context group with cross-origin documents — crucially cutting the window.opener relationship that enables some XS-Leaks and Spectre-adjacent process sharing.
Docs: MDN COOP, web.dev COOP/COEP.
The opener problem
// page A opens popup B
const w = window.open('https://other.example/oauth');
// historically B could touch window.opener (A) if same conditions allowed
Even without full DOM access, presence of opener relationships and shared process groups has been abused for timing attacks and tab-nabbing variants. rel="noopener" on links helps navigation cases; COOP hardens document policy at the HTTP layer.
Header values
Cross-Origin-Opener-Policy: same-origin
| Value | Effect |
|---|---|
unsafe-none |
Default; no COOP isolation |
same-origin |
Only same-origin documents share the group; cross-origin popups detach |
same-origin-allow-popups |
Softens popup UX for OAuth-like flows while keeping many benefits |
With same-origin, a cross-origin popup often gets window.opener === null from the opener’s perspective after navigation policies apply — test your OAuth/payment popups.
Pairing with COEP
Cross-origin isolation typically needs:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Then:
crossOriginIsolated; // true
COOP alone helps opener isolation; COEP addresses embeddability of cross-origin resources. See COEP.
OAuth and payment popups
If login breaks after enabling COOP:
- Try
same-origin-allow-popupson the opener document. - Prefer redirect based OAuth over fragile opener callbacks.
- Use
postMessagewith explicit origin checks after popup return — postMessage security.
// child
window.opener?.postMessage({ type: 'oauth-done' }, 'https://app.example.com');
// parent
window.addEventListener('message', (e) => {
if (e.origin !== 'https://auth.example.com') return;
// handle
});
Reporting
COOP can be paired with reporting endpoints (Report-To / Reporting API) during rollout to catch unexpected breaks — same operational story as CSP report-only.
Interview out-loud
“COOP same-origin isolates the browsing context group so cross-origin documents don’t share opener relationships the way unsafe-none does. With COEP it enables crossOriginIsolated. Watch OAuth popups — same-origin-allow-popups or redirect flows fix most breaks.”
Popups after COOP
OAuth “login with popup” often breaks first. Prefer full-page redirect with state parameter for new work. If popups remain, verify same-origin-allow-popups on the opener and that the popup’s COOP doesn’t immediately sever communication before your postMessage handshake completes. Always fall back to redirect.
Debugging checklist
- Reproduce the OAuth or payment popup flow on a staging build with COOP enabled.
- Log
window.openeron both sides after navigation settles. - Try
same-origin-allow-popupson the opener document only. - Confirm the popup document’s own COOP is not over-restrictive for the handshake window.
- Keep a full-page redirect path behind a feature flag for emergencies.
When isolation is required for SharedArrayBuffer, document that product flows depending on opener-based messaging must migrate to postMessage with explicit origins or to redirects. Do not silently ship COOP on marketing day without QA on every login provider you support.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Cross-Origin Embedder PolicyCOEP require-corp / credentialless: cross-origin isolation, SharedArrayBuffer, and embedding requirements.
- Content-Type and MIME SniffingWhy Content-Type matters, how MIME sniffing works, X-Content-Type-Options: nosniff, and XSS-ish pitfalls.
- CORS Explained for FrontendWhy the browser blocks cross-origin responses, what Access-Control-* headers mean, preflight, credentials, and how to fix real frontend errors.
- Feature Policy Legacy NotesFeature-Policy renamed to Permissions-Policy: migration notes, old header syntax, and what still matters.
- Permissions PolicyLock down camera, geolocation, payment, and other powerful features with Permissions-Policy headers and iframe allow.