I am implementing Facebook OAuth for user sign-in following facebook-login/guides/advanced/manual-flow. When the user clicks "Sign in with Facebook," a popup window opens at https://my-domain/login, which redirects to Facebook's OAuth URL (e.g., https://www.facebook.com/v21.0/dialog/oauth?...). Initially, window.opener correctly points to the parent window that opened the popup.

However, after the user completes the login (e.g., clicks "Continue as [Username]") and is redirected back to https://my-domain/login, window.opener unexpectedly becomes null. Since window.opener shouldn't become null during this process, this behavior is breaking my implementation, as I rely on window.opener.postMessage() to send the redirect URI back to the main window.

This issue occurs in all Android browsers (e.g., Chrome, Firefox, Opera) but works correctly on desktop browsers. Other OAuth providers like Google, Github, etc. works fine on both Android and Desktop browsers. Facebook works on Desktop browser, but window.opener becomes null in Android browser. In the network tab, I noticed that desktop browsers make requests to www.facebook.com, while Android browsers make calls to m.facebook.com. Why does window.opener become null on Android browsers, and how can I resolve this?

Additional Reproduction Steps:

  1. Enable remote debugging on an Android browser using Chrome DevTools.

  2. Open a new tab and run the following in the Console tab: window.open(LOGIN_PAGE_URL);

    Replace LOGIN_PAGE_URL with a site supporting Facebook login (e.g., https://leetcode.com/accounts/login/).

  3. In the popup window, run: window.opener;

    It correctly returns the parent window reference.

  4. Click "Sign in with Facebook." On the Facebook login page, window.opener still returns the correct reference.

  5. Complete the login. After redirecting back to the original page, window.opener unexpectedly becomes null. Because window.opener becomes null, I am unable to send redirect_uri by doing window.opener.postMessage() from popup window to my opener window.

    Example code to reproduce the same error:

    <!-- Parent window --> <html>   <body>     <button id="login-btn">Sign in with Facebook</button>     <script>       document.getElementById("login-btn").onclick = () => {         const popup = window.open("https://my-domain/login", "_blank", "width=600,height=600");         window.addEventListener("message", (event) => {           if (event.origin === "https://my-domain") {             console.log("Received message from popup:", event.data);           }         });       };     </script>   </body> </html> <!-- Popup window --> <html>   <body>     <script>       // Redirects to Facebook login       window.location.href = "https://www.facebook.com/v21.0/dialog/oauth?response_type=code%2Cgranted_scopes&client_id=CLIENT_ID&state=STATE_STRING&scope=public_profile%2Cemail%2Cuser_likes&redirect_uri=https://my-domain/login";       // After redirect back from Facebook       window.onload = () => {         if (window.opener) {           window.opener.postMessage({ redirect_uri: window.location.href }, "https://my-domain");         } else {           console.error("window.opener is null");         }       };     </script>   </body> </html> 

    Client ID can be retrieved by registering a web-app in https://developers.facebook.com/.

Tag:oauth-2.0, http-redirect, facebook, facebook-graph-api, window.opener

3 comments.

  1. Coch

    I recently faced the same issue.

    window.opener is null on some mobile browsers for security reasons.

    I used BroadcastChannel instead, and it works perfectly on every devices in my case.

    // In parent window: const channel = new BroadcastChannel('yourCustomChannel'); channel.onmessage = (event) => { if (event.data.startsWith(window.location.origin)) { window.location.href = event.data; } channel.close(); }; // In popup window: window.close(); const channel = new BroadcastChannel('yourCustomChannel'); channel.postMessage('https://you-redirect-url');

    Hope it helps :)

    1. A V

      Hi Coch, thanks for the reply. Unfortunately, I am dealing with popup and opener windows at different origins. Because of which, I am unable to use BroadcastChannel API. Are you aware of any such alternatives, which might also work when popup and opener window are at different origins.

    2. Coch

      To keep the same origin on both windows, I've created two Controllers which are used to open the popup and as a callback. 1. window.open('mycontroller') 2. Inside the popup, redirect to facebook login 3. After login, redirect to the callback In the callback, I close the popup and post the message in the broadcast channel. That way I've no origin issue. Hope it can suit to your needs.

Add a new comment.