facebook
Facebook Graph API: Authenticating In IFrame Applications
November 22, 2010
11

The latest Facebook API, dubbed Open Graph API , is a powerful replacement to the old API. However, the documentation (in particular regarding authentication) is not very clear. Hopefully this will help you get up to speed with what it takes to authenticate users.

This tutorial assumes that you have already setup your application on Facebook Developer section and it will only cover the new Open Graph Javascript library (all.js). The simplest way to know if you are using Open Graph API is to check which .js file you are using. If you see all.js, then you are using Open Graph API, if you see FeatureLoader.js, then you are using the Old Rest API. This tutorial is not useful if you are using the Old Rest API — sorry.

===============

IMPORTANT UPDATE NOTES (Dec 2011)

Due to changes on Facebook API, change these elements to get this to work on OAUTH2.0:

  • Change response.session to response.authResponse.
  • Change getSession in .js to getAuthResponse.
  • perms is now called scope.

The source linked at the end of this guide has the changes already implemented, but the guide still refers to the old names.
===============

Before going into the details, let’s list the possible scenarios that might occur when user enters your application:

  • Scenario 1: User is not logged in to Facebook.
  • Scenario 2: User is logged in and has not given access to your application.
  • Scenario 3: User is logged in and has given access to your application.

In pseudo-code, here’s how to handle them:

Initialize Open Graph API.
call FB.init()
call FB.getLoginStatus()

check the result of FB.getLoginStatus as follows:
if (response.session is "connected") then
{
  check if (user has the required permissions)
  {
     If so, hide login button and continue running the application
  }
  else
  {
    Prompt user for permissions.
  }
}
else if (response.session is not "connected") then
{
  Prompt user to login, using FB.login()
  if user does not login even after prompted
  {
     Warn user or show login button (or whatever you want to do).
  }
  else if (repose.perms is null or response.perms does not contain all the requested permissions)
  {
     Warn user, prompt for permissions.
  }
}

In more details, follow these steps:

Step 1

Initialize the Open Graph library as explained in http://developers.facebook.com/docs/reference/javascript/FB.init

<div id="fb-root"></div>
<script>
  window.fbAsyncInit = function()
  {
    FB.init({
      appId  : 'YOUR_APP_ID',
      status : true, // check login status
      cookie : true, // enable cookies to allow the server to access the session
      xfbml  : true  // parse XFBML
    });

  };

  (function() {
    var e = document.createElement('script');
    e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
    e.async = true;
    document.getElementById('fb-root').appendChild(e);
  }());
</script>

Step 2:

After the API is initialized, we will check whether the user is logged in to Facebook or not. Here’s a tricky part: You might think that setting status parameter in FB.init() to true (ie: the line status : true above) and subscribing to ‘auth.statusChange’ event will tell you if the user is connected to Facebook or not, but the behavior has been inconsisten for me.

Therefore, let’s not use that and instead, we will use FB.getLoginStatus() to get the login status, like below (line 13).

<div id="fb-root"></div>
<script>
  window.fbAsyncInit = function()
  {
    FB.init({
      appId  : 'YOUR_APP_ID',
      status : true, // check login status
      cookie : true, // enable cookies to allow the server to access the session
      xfbml  : true  // parse XFBML
    });

    FB.Event.subscribe('auth.statusChange', onFacebookStatusChange);
    FB.getLoginStatus(onFacebookInitialLoginStatus);
  };

  (function() {
    var e = document.createElement('script');
    e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
    e.async = true;
    document.getElementById('fb-root').appendChild(e);
  }());

  /*
   * Callback function for FB.getLoginStatus call.
   */
  function onFacebookInitialLoginStatus(response)
  {
    alert("onFacebookInitialLoginStatus(), "
      + "nresponse.status="+response.status
      +" nresponse.session="+response.session
      +" nresponse.perms="+response.perms);
  }

  /*
   * Callback function for 'auth.statusChange' event.
   */
  function onFacebookStatusChange(response)
  {
    alert("onFacebookStatusChange(), "
      + "nresponse.status="+response.status
      +" nresponse.session="+response.session
      +" nresponse.perms="+response.perms);
  }
</script>

Try that and you should see the following results:

If the user is not connected to Facebook (Scenario 1 above), the output is like below (note that response.status can either be unknown or notConnected):

onFacebookInitialLoginStatus()
 response.status=notConnected
 response.session=null
 response.perms=undefined

If the user is connected to Facebook, but has not used your application before (Scenario 2 above), the output is like below:

onFacebookInitialLoginStatus()
 response.status=connected
 response.session=[object Object]
 response.perms=undefined

If the user is connected to Facebook and has authorized your application and has given the required permissions, then the output is something below:

onFacebookInitialLoginStatus(),
 response.status=connected
 response.session=[object Object]
 response.perms=
 {"extended":
  ["read_stream",
   "status_update",
   "photo_upload",
   "video_upload",
   "create_note",
   "share_item",
   "publish_stream"
  ],
  "user":[],
  "friends":[]
  }

You can read more about FB.getLoginStatus() here: http://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus.

In a nutshell, this step handles checking for Scenario 1. Now, the next question is: how do you prompt user to login and grant permissions (the response.perms part)? This will be answered in the next step.

Step 3

Add the following code to prompt user to login:

  function facebookLogin()
  {
    FB.login(onFacebookInitialLoginStatus, {perms:'read_stream,publish_stream'});
  }

Then, we hook this function to the result of response.status in onFacebookInitialLoginStatus(). If response.status is not “connected”, then we should call that function.

  /*
   * Callback function for 'FB.getLoginStatus' call.
   */
  function onFacebookInitialLoginStatus(response)
  {
    alert("onFacebookInitialLoginStatus(), "
      + "nresponse.status="+response.status
      +" nresponse.session="+response.session
      +" nresponse.perms="+response.perms);
   if (response.status!="connected"  || !response.session)
     facebookLogin();
  }

Run the example without being logged in to Facebook, and you should see this:

If you go ahead and login, you will be prompted to grant permissions. Note that perms contains the permissions that you want user to grant and I am using read_stream and publish_stream only as examples. The actual values depend on what permissions you need in your app.

Where does these permissions get defined? It’s in the FB.login() call above, under {perms:’read_stream,publish_stream’}). You can request more permissions if needed, the values are separated by comma.

You can read about FB.login here: http://developers.facebook.com/docs/reference/javascript/FB.login.

You can see other possible permissions that you can requests here:http://developers.facebook.com/docs/authentication/permissions.

You can try the example here: http://www.permadi.com/tutorial/facebook-graph-api-login-example/step3.html

Step 4

Assuming users followed the normal flow and they proceed to login (or they are already logged in) and granted permissions, then our job is done. But what if the user decides not to login or they login but decide not to grant permissions? Depending on the application, you might allow user to continue with limited functionality, warn them, or redirect them to other page.

In the example in Step 3, the user will keep being prompted to give permission because FB.login() is set to callback onFacebookInitialLoginStatus and onFacebookInitialLoginStatus will see that status.connected is “unknown”. This has the potential of annoying the user. We’ll see how to rectify that in Step 5.

Another option is to leave a login button so that user can still login if they change their mind. This is the code to show the login button:

<div id="fb-login-button-div">
Please login to enjoy all the features of this application:
<fb:login-button show-faces="false" perms="read_stream,publish_stream"></fb:login-button>
</div>

Note here that the perms value should be the same as the one you used in the FB.login call in Step 3.

The button will look like below:

However, how about the users that has already logged in? We do not want to show this button if they are already logged in, so we’ll hide it on the next step.

Step 5

To hide the login button, you can enclose it on a div element and hide it when user did login and authenticate your application.

Alternatively, you can hide the div and show it once you detect that the user refused to log in. However this is not encouraged, having this button is a good idea because depending on user’s browser configuration, calling FB.login() automatically (like in Step 3) is not always reliable. Some browsers blocks pop-ups windows unless the popup is trigerred by user action, like clicking a button or a link. With the Login button there, such user can pops the login window and not be locked out. Also, this allows stubborn users who refuses to login to change their mind.

 /*
   * Callback function for 'FB.getLoginStatus' event.
   */
  function onFacebookInitialLoginStatus(response)
  {
    alert("onFacebookLoginStatus(), "
      + "nresponse.status="+response.status
      +" nresponse.session="+response.session
      +" nresponse.perms="+response.perms);
    if (response.status=="connected" && response.session)
    {
      alert("You are all set.");
      var loginButtonDiv=document.getElementById("fb-login-button-div");
      loginButtonDiv.style.display="none";
    }
    else
    {
      facebookLogin();
    }
  }

To prevent user from being prompted to login after they refused, we should change the code from Step 4 slightly so that FB.login calls a different callback. Below, I created a callback named onFacebookLoginStatus, which is very similar to onFacebookInitialLoginStatus except it simply warns user if they decide not to login or grant permission to our application.

  function facebookLogin()
  {
    FB.login(onFacebookLoginStatus, {perms:'read_stream,publish_stream'});
  }

  /*
   * Callback function for 'FB.login' event.
   */
  function onFacebookLoginStatus(response)
  {
    alert("onFacebookLoginStatus(), "
      + "nresponse.status="+response.status
      +" nresponse.session="+response.session
      +" nresponse.perms="+response.perms);
     if (response.status=="connected" && response.session)
    {
      alert("You are all set.");
      var loginButtonDiv=document.getElementById("fb-login-button-div");
      loginButtonDiv.style.display="none";
    }
    else
    {
      alert("Please login to enjoy this application.");
    }

  }

The full working example and Javascript code can be seen in (use View Source on your browser):

http://www.permadi.com/tutorial/facebook-graph-api-login-example/step4.html

The same code will also work in the Facebook frame: http://apps.facebook.com/login-example/.

Some Opera browsers issue and fix: http://www.permadi.com/blog/2011/02/facebook-graph-api-in-opera/

===============

IMPORTANT UPDATE NOTES

Due to changes on Facebook API, change these elements to get this to work on OAUTH2.0:

  • Change response.session to response.authResponse.
  • Change getSession in .js to getAuthResponse.
  • perms is now called scope.

The source link below has the changes already implemented, but the guide still refers to the old names.
===============

The following example have been updated with the above change: http://www.permadi.com/tutorial/facebook-graph-api-login-example/step4.html