BroadcastChannel inside a cross origin iframe doesn't work in Safari & Firefox

793 Views Asked by At

I have two sites with different origins. Let it be foo.com and bar.com. Site foo.com fires messages through BroadcastChannel with 'payment-info' name. I also have an iframe, hosted on foo.com which is built in bar.com. Here's iframe code:

<html><head><script type="text/javascript">
    (function () {
        const bc = new BroadcastChannel('payment-info');

        bc.addEventListener('message', (m) => {
            const data = JSON.parse(m.data);
            data.channel = 'payment-info';

            if (window.top !== window) {
                window.top.postMessage(JSON.stringify(data), '*');
            }
        });
    })();
</script></head><body></body></html>

So iframe subscribes to 'payment-info' broadcast channel and when it fires, iframe post a message to it's parent window aka bar.com with some information.

On bar.com side I just listen to 'message' event and call 'receiveMessage' function with JSON.parse

window.addEventListener('message', function (message) {
            receiveMessage(message);
});

It's expected to work on my site bar.com in all browsers. It doesn't work in Safari and Firefox but works in Chrome.

I combined code from several files of index.html, index2.html and iframe.html which I used to test it locally in one file. index.html and iframe.html are considered to be from one origin and index2.html is from another. Unfortunately it's impossible to test it just as plain HTML/JS without two different servers with different domains

<!--INDEX CODE-->
<!doctype html>
<html lang="">

<head>
  <meta charset="utf-8">
  <title></title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <meta property="og:title" content="">
  <meta property="og:type" content="">
  <meta property="og:url" content="">
  <meta property="og:image" content="">

  <meta name="theme-color" content="#fafafa">
</head>

<body>
<p>index page</p>
<a href="/page.html">link</a>

<script>
  let i = 0;
  const bc = new BroadcastChannel('payment-page');

  function sendItem() {
    i+=1;

    const message = '{"message":"Hello from the new window!"}';
    if (window.opener) window.opener.postMessage(message, '*');

    const data = { message: `Hello from broadcast ${i}` };
    console.log(JSON.stringify(data));

    bc.postMessage(JSON.stringify(data))

    console.log(message)
  }
</script>



<button onclick="sendItem()">send item</button>
</body>

</html>
<!--END OF INDEX CODE-->

<!--IFRAME CODE-->
<html><head><script type="text/javascript">
  (function () {
    const bc = new BroadcastChannel('payment-page');

    console.log('broadcast channel is created', bc)

    bc.addEventListener('message', (m) => {
      console.log('proxy: receive message ', m);

      const data = JSON.parse(m.data);
      data.channel = 'payment-page';

      if (window.top !== window) {
        // Inside iframe. Proxy to top.
        console.log('proxy: send to parent');

        window.top.postMessage(JSON.stringify(data), '*');
      }
    });
  })();
</script></head><body></body></html>

<!--END OF IFRAME-->

<!--INDEX2 CODE-->
<!doctype html>
<html class="no-js" lang="">

<head>
  <meta charset="utf-8">
  <title></title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>

  <iframe
          width="100"
          height="100"
          src="http://domain-1.com:3000//iframe.html"
  ></iframe>

  <script>
   window.addEventListener('message', function (message) {
      if (message.data && typeof message.data === 'string') {
        console.log(JSON.parse(message.data))
      }
    });
  </script>
</body>

</html>
1

There are 1 best solutions below

1
On

Broadcast channel only works between pages in the same origin.

The Broadcast Channel API allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin.

https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API