Wednesday, September 1, 2010

Facebook application development - problems with authentication.

As you all know, in order for a facebook application to gain access to extended profile information, it needs to be authenticated. The barebones example of how to do this using PHP SDK can be found here. Basically the idea behind the authentication process is following:
  1. The app needs to check whether it has a valid session with the user by calling Facebook::getSession() method. If null is returned - proceed to authentication.
  2. To authenticate, the app needs to call the Facebook::getLoginUrl(array(set of params)) method and have user click this url or redirect him to it.
  3. User will be presented with a dialog where he will be asked to grant the app access to his profile.
  4. After clicking "Allow", user will be redirected to the url, specified in the 'next' param.

According to the documentation that should be it. However, I, along with many other developers, ran into problems of getting the app authenticated. The problem is well documented here. Basically, it seemed like the app was failing to carry over the acquired session between HTTP requests. After hours and hours of reading inaccurate and outdated documentation, I noticed that after I allow my application to access my profile, it redirects itself to the page, I specified in the 'next' param (as expected), but it also adds the variable to the GET reuest, called 'session'. The value of this variable is the contents of the acquired session in the JSON format.

I am developing my app using an iframe. There is a php script, that generates a landing page, which contains an iframe, where the actual app is being loaded. I decided to retrieve that 'session' variable from the GET request, and stick it into the actual $_SESSION, where it could be accessible by the rest of the app.

Here is how it goes:

<?php if (@$_GET['session']) {
session_start();
$_SESSION['session'] = json_decode(stripslashes($_GET['session']),true);
} ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<iframe src ="my app landing url" width="750px" height="700px">
<p>Your browser does not support iframes.</p>
</iframe>
</body>
</html>



And this is the code that deals with the application state:



$this->fb = new Facebook(array(
'appId' => APP_ID,
'secret' => APP_SECRET,
'cookie' => false,
));

$session = $this->fb->getSession(); //first try to get session the regular way

if (!$session) {
$this->fb->setSession($_SESSION['session'], false); //set session
$session = $this->fb->getSession(); //make sure it is valid
}

if (!$session) {
$par['req_perms'] = "publish_stream, offline_access";
$par['next'] = "where to redirect after user clicks 'Allow'";
$par['canvas'] = 1;
$par['fbconnect'] = 0;
$url = $this->fb->getLoginUrl($par);
echo "<script type='text/javascript'>top.location.href = '$url';</script>";
exit;
}
This should do it. Comment, let me know what you think.

4 comments:

  1. You are seriously my favorite person in the world right now. Thank you so much for writing this up. If you're ever in Florida let me know and I'll treat you to a beer.

    Also, for anyone who finds this gem of a post, you must use top.location.href in your iframe application to keep that facebook logo from appearing.

    ReplyDelete
  2. This saved my day too. Thanks so much!

    ReplyDelete
  3. Thanks a lot. You really save my day!

    ReplyDelete
  4. I have two questions for you.

    $this->fb->setSession($_SESSION['session'], false); //set session

    question 1. what goes in the 'session' field ? the facebook userid?

    $par['next'] = "where to redirect after user clicks 'Allow'";

    question 2. what is the proper URL to use here?

    thanks for any help

    ReplyDelete