Search code examples
javascriptauthenticationoauth-2.0instagram-api

Instagram oAuth Authentication postMessage issue only with Mobile Browsers


I have an Ionic 2 app ("native") that also runs on the browser for both mobile devices and desktop browsers. This app provides authentication via Instagram, Google, Facebook and Twitter. On the API side this is handled by hapi.js and the bell plugin.

Now, I've been fighting an issue with Authentication on Instagram when doing it on a mobile browser.

When this app runs on the browser instead of relying on the Ionic provided auth mechanisms we've implement our "browser" fallbacks to do it.

We've been having no major issues with any of the implementations other than Instagram, which was previously working just fine.

We have this code that is supposed to open a new window (tab on the browser) to deal with the social network login page and when we get back the auth token then proceed to close the tab and authenticate the user on the app.

On the app side, handling this tab switch and communications behaviour looks essentially like this:

private requestToken(tokenEndpoint, resolve, reject) {
    let messageReceived = false;
    let win = window.open(this.globals.BASE_URL + tokenEndpoint,
        '_blank', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=500, height=300');

    // Await auth message
    window.onmessage = (e) => {
        let credentials;
        messageReceived = true;

        try {
            credentials = JSON.parse(e.data);
        }
        catch (error) {
            credentials = e.data;
        }

        return credentials ? resolve(credentials) : reject();
    };

    let interval = window.setInterval(() => {
        try {
            // win is already null after closing first tab
            if (win == null || win.closed) {
                window.clearInterval(interval);

                if (!messageReceived) {
                    reject();
                }
            }
        }
        catch (e) { }
    }, 1000);
}

My API will return the required data to the frontend with:

<script>window.opener.postMessage('{0}', '*');window.close();</script>

, where {0} is my required auth data.

For any other social network, this will open a new tab with address about:blank and will then change to the correct url for inputting the username/password. When that's done, the server hits back with that little script and the phone closes the tab passing the data back to the app. It works flawlessly.

HOWEVER,

For Instagram the behaviour is different. A new tab will open, it will close immediately and a new one will appear, where I'll input my data back. The problem is that by the time the server gets back with the script my window.opener is null and a reference to the original page is lost which prevents me from getting the auth data back.

How can I overcome this? How can I force the original tab to not close but rather behave as the other ones and just navigate to the IG login page? Does IG send back a 301 or 302 reply? If it does, I've been unable to catch it so far.


Solution

  • For those that end up here, the solutions was to use window.parent.parent.postMessage() rather than rely on window.opener.postMessage()