skip to content
Jerrie Pelser's Blog

Return popup window response with the Broadcast Channel API

/ 5 min read

Introduction

The Broadcast Channel API is a Web API that allows communication between browser windows and tabs on the same origin.

In this blog post I will demonstrate how you can use it to communicate a response from a browser popup window back to the main window which opened the popup.

Background

In Cloudpress, I allow users to connect their Content Management System (CMS), Google Drive, and Notion accounts. Some of these applications uses OAuth 2.0 (or OpenID Connect) for authorization. When a user connects one of these applications, I initiate the OAuth 2.0 Authorization Code flow in a popup window.

Once the user has completed the authorization flow, I need to be able to access the details for the newly connected account inside the browser tab that initiated the flow. To achieve this, I use the Broadcast Channel API to communicate back from the popup window to the originating browser tab.

The following diagram describes this flow better:

The authorization flow using a popup window
  1. The user uses Cloudpress and wants to export a document from their Google Drive. They do not have a Google Drive connected, so they click the “Connect Account” button.
  2. The Google OAuth flow is initiated in a popup window and the user authorizes Cloudpress to access their Google account.
  3. The main application browser tab is notified that the user completed the authorization flow, and refreshes the list of available accounts using XMLHttpRequest (i.e. an AJAX call).

In the scenario above, I use the Broadcast Channel API to notify the main application browser tab once the authorization flow is complete and the popup window closes.

Why use a popup window?

A quick sidenote about why I chose to open a popup window for the authorization flow, rather than initiate the authorization flow inside the current browser tab:

  1. Cloudpress is a React application. If I navigate the user away from the current page in Cloudpress to perform the authorization flow in the same window, upon redirect, the entire React application will need to load again.
  2. Cloudpress has many multistep processes for exporting content. If I launch the authorization flow in the same browser tab as Cloudpress, I will interrupt the user’s current flow. Having it open in a popup window is less interrupting.

If you’re curious and want to see this in action, look at our video for connecting your Notion account to Cloudpress to get a better understanding of the flow from the user’s point of view.

Using the Broadcast Channel API

The Broadcast Channel API itself is pretty simple. The first thing you need to do is to create a channel by calling the constructor and passing the name of the channel as the name parameter:

const bc = new BroadcastChannel('add-oauth-connection-channel');

The second step is to listen for events by connecting a handler to the onmessage event or using the addEventListener method.

// Register a handler in the window where you want to listen to events
bc.onmessage = (event) => {
console.log(event);
};
// Alternatively, you can add an event listener by calling the addEventListener method
bc.addEventListener("message", (event) => {
console.log(event);
});

To broadcast a message to the channel, call the postMessage method. This method takes any kind of Object as a parameter.

// Broadcast an event to all listeners by calling the postMessage method
bc.postMessage("This is a test message.");

What this looks like in Cloudpress

In the scenario described previously, where I use this when connecting external accounts via the OAuth 2.0 Authorization Code flow, this looks as follows:

First, in the Cloudpress frontend (a React application), I create a BroadcastChannel instance and hook up the onmessage event which uses the Fetch API to refresh the list of accounts. I also make sure to clean up after myself by calling the close() method to terminate the connection to the underlying channel.

// In the Cloudpress frontend (a React application)
useEffect(() => {
const bc = new BroadcastChannel('add-oauth-connection-channel');
bc.onmessage = (event) => {
// Do a fetch request to update the list of available accounts
};
return () => {
bc.close();
};
});

In the Cloudpress backend, an ASP.NET Core application which handles the OAuth 2.0 Authorization Code flow, once the flow is complete, I render the following HTML response.

<!-- In the Cloudpress backend (an ASP.NET Core application) -->
<script>
const bc = new BroadcastChannel('add-oauth-connection-channel');
bc.postMessage("[The message to send to the frontend]");
window.close();
</script>

This will create a Broadcast channel with the same name as the Cloudpress frontend and broadcasts a message to the frontend. After broadcasting the message, I close the popup by calling the Window.close() method.

What about using window.postMessage?

Another option to do this could be to use the postMessage() method of the Window object. This is what I did for the longest time in Cloudpress, but I suddenly started receiving support requests from users that they were unable to connect their accounts.

Looking into this it seemed that, due to browser security settings, this approach stopped working for many users. So, I had to find a different approach and came across the Broadcast Channel API.

The Broadcast Channel API has worked reliably for me and is arguably a more modern and correct approach. It has been widely available across browsers since March 2022.

If you currently use the Window.postMessage() event, I suggest you look into replacing it with the Broadcast Channel API.

Conclusion

In this blog post, I described how I use the Broadcast Channel API to communicate a response back from a browser popup window to the window which opened it.

This is one use specific use case, but you can use the Broadcast Channel API in a number of different scenarios where you want to communicate between different browser windows or tabs of your application.