Facebook Application Authentication

I’ve just spent some frustrating hours working with Facebook. Cutting a long story short, the objective was to integrate the News module of CMSMS with a Facebook page so that summaries of news stories would be posted onto the Facebook page. It’s been frustrating due to the number of bits that I had to pull together to make it work. This post is intended to help anyone else going through the process of integrating an application with the Facebook Graph API from a PHP server.

The Graph API it’s self is pretty simple to use and the Facebook Graph Explorer provides a great way of experimenting with the API. The bit that cost me time is obtaining an Access Token. In the Graph Explorer, this is achieved by just pressing a button. Within a real application, it’s not quite as simple! The process of getting a an access token is fully documented at https://developers.facebook.com/docs/howtos/login/server-side-login/ but there were a number of things I had to hunt for in addition. This post builds upon that page, indeed follows it’s structure but adds the bits I felt were not obvious.

I’ve stayed with the structure of the Facebook documentation and you should refer to that along with this post.The steps outlined by Facebook are

Step 1. Create a Facebook App

Step 2. Create basic PHP page

Step 3. Redirect the user to the Login Dialog to get an authorization code

Step 4. Add Permissions to Login Dialog request

Step 5. Handle the response from the Login Dialog

Step 6. Exchange the authorization code for an Access Token

Step 7. Use the Access Token by performing an API call

Step 1. Create a Facebook App

The documentation at : https://developers.facebook.com/docs/howtos/login/server-side-login/. Is a great start. However, there was extra information that I had to hunt for.

I needed to define my application as “Website with Facebook Login” and then set both the Site url and App Domains fields to match the domain where my PHP code was running.

Step 2. Create basic PHP page

This “basic” PHP page needs to do two things:

a) Request authentication for the user

b) Once authenticated, perform the application logic

Step 3. Redirect the user to the Login Dialog to get an authorization code

Perhaps the single most crucial step

The PHP page get’s invoked in two different ways. The first is directly from our application (user clicks a link), the second is as a call-back from the Facebook authentication dialog. We determine which of these it is by examining a $_REQUEST parameter called code

$code = $_REQUEST["code"];
if(empty($code)) {
	// Application needs to get an authentication code
} else {
       // It's a redirect from the Facebook authentication dialog
}

If the code parameter is not present, then your application MUST request one. (Strictly: you must redirect the user to the Facebook authentication dialog so that they can request one).

$dialog_url = "https://www.facebook.com/dialog/oauth?client_id="
		. $this->app_id . "&redirect_uri=" . urlencode($this->my_url) . "&state="
		. $_SESSION['state']
		. "&scope=" . $scope;

echo("<script type="text/javascript">// <![CDATA[top.location.href='"
       . $dialog_url . "'// ]]></script>");

[This relies on JavaScript being enabled. You could use location header(Location: $location); if no headers have yet been written]

Notice that one of the request parameters is &state. This is a random number which we add to the request to prevent Cross SiteRequest Forgery (CSRF). It needs to be stored in the $_SESSION so we can check it when we receive the authentication code back from Facebook in step 6.

$_SESSION['state'] = md5(uniqid(rand(), TRUE)); // CSRF protection

Step 4. Add Permissions to Login Dialog request

Step 4 is actually inluded in the previous step. It’s just the value of the scope parameter which is a list of required permissions. To get the name of the permissions: look at the names of the permissions in the dialog displayed from the Graph Explorer when you click Get Access Token

In our case, to update status on a page we needed:

$scope="publish_actions,manage_pages,publish_stream";

Step 5. Handle the response from the Login Dialog

When the user was redirected to the Facebook login dialogue, a redirect URL ( redirect_uri ) was specified. Once authentication is complete the page specified by that URL will be loaded. In our case, that is the same page we’ve been working with already.
If authentication was granted, the $_REQUEST["code"] will now contain a temporary authentication code.

$code = $_REQUEST["code"];

if(empty($code)) {
	// Application needs to get an authentication code
} else {
	// It's a redirect from the Facebook authentication dialog
}

Step 6. Exchange the authorization code for an Access Token

The code value is only temporary. You must exchange it for an access token.

At this point, you have an authentication code but you must swap it for an access token. We first make sure that the $_REQUEST['state'] value matches the one in our session to detect attempts at CSRF. Then, we use the Graph API to request the access token.

if($_SESSION['state'] && ($_SESSION['state'] === $_REQUEST['state'])) { // Check the state variable matches the one supplied to the authentication dialog
    $token_url = "https://graph.facebook.com/oauth/access_token?"
	    . "client_id=" . "YOUR_APP_ID"
            . "&redirect_uri=" . urlencode("URL_OF_YOUR_PAGE")
	    . "&client_secret=" . "YOUR APP_SECRET"
            . "&code=" . $code; // The authentication code supplied in $_REQUEST["code"];

    $response = file_get_contents($token_url); // Make the request
    $params = null;
    parse_str($response, $params); // Parse the results
    $accessToken = $params['access_token']; // Save the access token
} else {
    // Don't use the token, it may be a CSRF attack
}

Step 7. Use the Access Token by performing an API call

You can now use the token to make a request with the Graph API. The example is adding a link to the specified Facebook page.

$url = 'https://graph.facebook.com/[YOUR_PAGE_ID]/links';
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, array("access_token" => $accessToken, // The token previously acquired
                                           "message" => $statusMessage,    // The text to go with the link
                                           "link" => $link,                // The link URL
                                           "description" => $content));    // Detailed text
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$result = curl_exec($ch);
curl_close($ch);

// Parse the results from JSON into an object
$obj = json_decode($result);

if(!empty($obj->{'id'})){ // ID is the Facebook ID of the new item
    echo ("</pre>
<h2>Success. Story is now linked on the Page</h2>
<pre>
");
} else {
    echo ("</pre>
<h2>Oh bother, it did not work. Error = " . $result . "</h2>
<pre>
");
}

Debugging

Naturally, I spent a lot of time debugging this. Two techniques were particularly useful.

  1. Use the Graph Explorer it allows you to see exactly how your requests are being handled.
  2. Dump out the response data using echo. It quite often gives you a detailed breakdown of why Facebook rejected your request.

Please leave a comment if you have anything to add to this or would like some help.

Mike

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Leave a Reply