Victory is mine!
There is an almost wholly undocumented Facebook feature dealing with iframe sessions, that I found a vague reference to in my research. This page doesn't really explain it well however, and only after several hours of watching various session keys in my iframe was I able to figure out what was going on.
Previously, my iframe app was receiving the usual round of fb_whatever
parameters when the initial iframe load occurred. So in my application, I was doing this on every request:
if (isset($_REQUEST['fb_sig_session_key'])) {
$_SESSION['fb_sig_session_key'] = $_REQUEST['fb_sig_session_key'];
}
if (! empty($_SESSION['fb_sig_session_key'])) $this->facebook->api_client->session_key = $_SESSION['fb_sig_session_key'];
This code would receive the fb_sig_session_key
on the initial app load, and I would squirrel it away into a local $_SESSION
for use with the API. Storing it in the local session is necessary, because fb_sig_session_key
never gets passed in again unless you reload the entire app iframe.
So the problems occurred when this session key expired an hour or so later.
After looking at the vague reference page, I started examining all the $_REQUEST
variables I was getting. It turns out that even on an internal link inside your iframe app, Facebook modifies the request to pass along some parameters. For some reason, they have an entirely different, but also valid session key that comes along with every iframe request!
This parameter is named after your Facebook Application api key. So if your application API key is "xyz123", every request inside your iframe gets a parameter called xyz123_session_key
(as well as a few others, like xyz123_expires
and xyz123_user
).
After watching the associated expiry time for the main session (the original fb_sig_session_key
) and this iframe-only session (xyz123_session_key
), the light at the end of the tunnel appeared: the iframe-only session key expiry time actually gets updated occasionally. I haven't determined when or how (I assume it's an Ajax ping at some point), but nonetheless, it refreshes.
I waited for the original fb_sig_session_key
session to expire, and sure enough the friend-related pages in my app started coughing up errors. At that point, I switched my locally-stored session key to the new iframe-only xyz123_session_key
, and the problem was solved. That session works just as well as the original!
So, my final code fix is to store the session key locally as follows:
$iframeSessionKeyName = $CONFIG['facebook']['apiKey'] . '_session_key';
if (isset($_REQUEST[$iframeSessionKeyName])) {
$_SESSION['fb_sig_session_key'] = $_REQUEST[$iframeSessionKeyName];
}
else if (isset($_REQUEST['fb_sig_session_key'])) {
$_SESSION['fb_sig_session_key'] = $_REQUEST['fb_sig_session_key'];
}
if (! empty($_SESSION['fb_sig_session_key'])) $this->facebook->api_client->session_key = $_SESSION['fb_sig_session_key'];
This gives preference to the "iframe-only" key.
Edit: My original assumption that the "iframe-only" key was updated via some kind of Ajax method was wrong, it turns out these values are set into a cookie by Facebook. This leads to some cross-domain problems when using these cookies. Setting a P3P cookie policy will alleviate this with most browsers, except Safari. There is still no good work around for Safari.