Nov
22
2010

 

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

[c]
<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>
[/c]

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).

[c]
<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>
[/c]

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):

[c]
onFacebookInitialLoginStatus()
response.status=notConnected
response.session=null
response.perms=undefined
[/c]

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

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

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

[c]
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":[]
}
[/c]

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:
[c]
function facebookLogin()
{
FB.login(onFacebookInitialLoginStatus, {perms:’read_stream,publish_stream’});
}
[/c]

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.
[c]
/*
* 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();
}
[/c]

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:
[c]
<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>
[/c]

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.

[c]
/*
* 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();
}
}
[/c]

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.

[c]
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.");
}

}
[/c]

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

11 Responses to “Facebook Graph API: Authenticating In IFrame Applications”

  1. [...] Facebook Graph API: Authenticating In IFrame Applications [...]

  2. Thank you SO much for this! You have no idea (or maybe you do) how long I’ve been searching for a blow-by-blow tutorial on how all of this works. You’ve single-handedly answered every one of my questions every step of the way– Thanks for posting this!

  3. [...] going straight to the wall posting code, the initialization of the application can be read here: here and here. Your application needs to have publish_stream permission to post to [...]

  4. [...] process here but you can read about it here: http://www.permadi.com/blog/2010/11/facebook-open-graph-api-authenticating-in-iframe-applications/What this does is to open the [...]

  5. Two days of searching and this is the *first* coherent piece of documentation I’ve seen for *any* FB SDK. Thank you.

    By the way, the direct call to FB.login() is rejected by some browsers (Chrome, at least, for me) because it’s a popup not initiated by a direct user action. I just display the login button instead of calling FB.login manually.

  6. Hello,
    Currently, I am integrating facebook graph API to our site. i am using the template <fb:login-button autologoutlink="true" but it is inconsistent. But the login and logout toggle functions are not firing well. And I found your site while I am searching for a solution. But, your fully detailed code is alos failing. I just copied all the successfull html by going tto the link :http://www.permadi.com/tutorial/facebook-graph-api-login-example/step4.html
    and just changed app-id. but it is not giving the correct result. earlier also i tried another model of you.it is centerng the fb login window. these samples are working with the particular APP_ID only. If i just changed the APP_ID to my APP_ID, these samples are dying. I request you to enlighten me about what error I am doing.mY cutpaste logic is at :http://www.texasfiesta.in/B3/fbGraph.html. i am completely ignorant about alll this FB:API and all. This is my First touch with FB logic and i am failing in simple logi/logout event call back things.i have benefited by your sending stream with images from your site models.
    that's why I am requesting you to make the login/logout of my site perfect.

  7. Send me your page URL. Would be easier to diagnose.

  8. [...] example uses the Javascript Graph API (for an overview of using the API, you can read a tutorial here). Okay, so here are the outline of the steps to publish as a [...]

  9. Hello

    I found your code working on FF. On Opera the login dialog does not close after entering credentials and giving permissions. It’s not a XD proxy problem, it’s just a white page with the title the same as the parent.

  10. Apparently I didn’t have Flash installed, after installing I now get the known “XD Proxy” problem

  11. [...] example uses the Javascript Graph API (for an overview of using the API, you can read a tutorial here). There’s also an example Javascript page that pull access_tokens that I will describe [...]

Leave a Reply

*