Facebook JS SDK Progressive web app issue Facebook JS SDK Progressive web app issue google-chrome google-chrome

Facebook JS SDK Progressive web app issue


When your app is installed as a progressive web app, the Facebook login popup and the parent window (your app) can't communicate the way they do in a desktop environment.

You'll face this problem in other scenarios as well, e.g. when your app is launched using in-app browsers like Instagram's or Facebook's.

You can implement a server-based flow as suggested by another answer. You can also implement a custom redirect flow on the client side.

A custom redirect flow works without popups. When your user clicks a "Login" button, he/she is instead redirected to a Facebook login screen. After logging in, the user is directed back to your app using a URL that contains everything you need to verify the success or failure of the authentication.

How to create a custom redirect flow is described in the Facebook SDK documentation, under "Manually Building a Login Flow":

https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow

The idea is as follows:

You direct your users to the Facebook login dialog (not the popup launched by FB.login()), e.g. when they click a button:

https://www.facebook.com/v2.11/dialog/oauth?  client_id={app-id}  &redirect_uri={redirect-uri}  &response_type=token  &state={state-param}

If the user successfully grants your app the necessary permissions, he/she is redirected back to your app (the location is determined by {redirect-url}):

{redirect-uri}?code=<facebook-code>&state={state}#_=_

Then you app needs to figure out whether the login was successful or not. There are two ways to do this:

A) Read the query string of the current URL (see the code=<code> part -- this can be used to retrieve additional info about your user, or it can be sent to your backend server).

B) Use the Facebook SDK do retrieve the login status using FB.getLoginStatus(yourCallback)

If you're already using the SDK and FB.login(yourCallback), you can add yourCallback to FB.getLoginStatus as well. You can also support both a popup flow and a redirect flow depending on the user's device.

I suggest reading through the documentation entry I posted above for further information and options.


I kind of figured out a way to do this for FB. Used FB PHP SDK to generate a login url and opened the url on a child window and the whole login dialog & permissions thing happens and it redirects to my redirect_url where I pass the necessary data to parent window using window.opener.postMessage.

My redirect_url page is setup like this:

<?phpif ( ! session_id()) {session_start();}require_once "vendor/autoload.php";$_SESSION['FBRLH_state'] = $_GET['state'];$fb = new Facebook\Facebook(['app_id'                => 'FBID', // Replace {app-id} with your app id'app_secret'            => 'FBSECRET','default_graph_version' => 'v2.2',]);$helper = $fb->getRedirectLoginHelper();try {$accessToken = $helper->getAccessToken();} catch (Facebook\Exceptions\FacebookResponseException $e) {echo 'Graph returned an error: ' . $e->getMessage();exit;} catch (Facebook\Exceptions\FacebookSDKException $e) {echo 'Facebook SDK returned an error: ' . $e->getMessage();exit;}if ( ! isset($accessToken)) {if ($helper->getError()) {    header('HTTP/1.0 401 Unauthorized');    echo "Error: " . $helper->getError() . "\n";    echo "Error Code: " . $helper->getErrorCode() . "\n";    echo "Error Reason: " . $helper->getErrorReason() . "\n";    echo "Error Description: " . $helper->getErrorDescription() . "\n";} else {    header('HTTP/1.0 400 Bad Request');    echo 'Bad request';}exit;}$oAuth2Client = $fb->getOAuth2Client();$tokenMetadata = $oAuth2Client->debugToken($accessToken);$tokenMetadata->validateAppId('FBID'); // Replace {app-id} with your app id$tokenMetadata->validateExpiration();if ( ! $accessToken->isLongLived()) {try {    $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);} catch (Facebook\Exceptions\FacebookSDKException $e) {    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";    exit;}}$_SESSION['fb_access_token'] = (string)$accessToken;$tk = $_SESSION['fb_access_token']; ?><?= $tk;?><script type="text/javascript">window.opener.postMessage({token: '<?= $tk;?>'}, '*');window.close();</script>

In the parent window I have an eventListener which is listening to the postMessage using window.addEventListener("message", receiveMessage, false);and the receiveMessage function handles all the data as required. So any web app using standalone mode should be able to get data from child window.

Window postmessage can be used to pass data between cross-origins. More details on postMessage are here: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage