Facebook PHP SDK session lost, needs JS SDK refresh - php

Really strange, it seems like the Facebook session is lost ($user = 0) using the PHP SDK (v 3.2.2). The JS SDK needs to reload my page to recover the Facebook session. This problem occurs now and then, sometimes the Facebook session is lost, sometimes it works just fine.
session_start();
// Run Facebook API
$facebook = new Facebook(array(
'appId' => $config['facebook']['id'],
'secret' => $config['facebook']['secret']
));
// Fetch user
$user = $facebook->getUser();
if($user) {
try {
// Just to be sure, add access token to each request
$user['access_token'] = $facebook->getAccessToken();
// Fetch user details
$user = $facebook->api('/me?access_token='.$user['access_token']);
}
catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
The main problem is that $user = $facebook->getUser(); returns 0. However, as the user is actually connected, the JS SDK detects the auth.login event and reloads the page (another strange thing, I use auth.login because the auth.authResponseChange event keeps getting fired every second). Now $user = $facebook->getUser(); returns the user's uid.
window.fbAsyncInit = function() {
FB.init({
appId : appId,
channelUrl : '//domain.com/signon/channel.php',
status : true,
cookie : true,
xfbml : true
});
FB.Event.subscribe('auth.login', function(response) {
location.reload();
});
};
In Facebook Developer I defined the App Domain (domain.com) and Site Url (http://domain.com/). Already tried Site Url with/without trailing slash, didn't solve the problem.
Any idea what's going on, why the Facebook PHP SDK doesn't detect the user's session immediately / keeps losing the user's session and needs a reload? This problem really causes a bad UX.
Thanks a lot!
Robin

I've come accross the same problem lately, it seems that if after 5mins or so of inactivity you do a reload, the session does not persist. Sometimes it works, sometimes it doesn't.
I've been looking into it for about the last week, and the only solution I could think of was to use the JS SDK to do a page reload with:
FB.Event.subscribe('auth.login', function(response) {
window.location.reload();
});
But I agree, it's not a very elegant solution in terms of UX. You should pass the cookie param in the PHP SDK, and the oauth param in JS SDK, and see if that works (it didn't for me):
$facebook = new Facebook(array(
'appId' => $config['facebook']['id'],
'secret' => $config['facebook']['secret'],
'cookie' => true
));
AND
FB.init({
appId : appId,
channelUrl : '//domain.com/signon/channel.php',
status : true,
cookie : true,
xfbml : true,
oauth : true
});
Stranger even still, I re-downloaded the latest PHP SDK from Github and uploaded it to a sandbox environment (Apache, PHP 5.4). I ran the example (with the JS SDK) AS-IS and it has the same issue!
Now if the above just doesn't cut the mustard, I have some more suggestions.
CHANGING THE SDK UP A BIT
Firstly, passing
$facebook->getAccessToken();
will do you no good if $user returns 0. However, after doing a bit of digging around in base_facebook.php, I noticed that the method getCode() actually uses $_REQUEST to retrieve the authorization code from the query parameters.
from the PHP Manual, $_REQUEST is
An associative array that by default contains the contents of $_GET, $_POST and $_COOKIE.
BUT
It is very different to $_GET,$_POST or $_COOKIE.
This can be a bit of a bugger depending on your setup. So instead, find the function getCode() in base_facebook.php that looks like this:
protected function getCode() {
if (isset($_REQUEST['code'])) {
if ($this->state !== null &&
isset($_REQUEST['state']) &&
$this->state === $_REQUEST['state']) {
// CSRF state has done its job, so clear it
$this->state = null;
$this->clearPersistentData('state');
return $_REQUEST['code'];
} else {
self::errorLog('CSRF state token does not match one provided.');
return false;
}
}
return false;
}
and merge the query into a new array/variable (let's call it $code_array) to include the $_GET, $_POST & $_COOKIE arrays using array_merge() like so:
$code_array = array_merge($_GET,$_POST,$_COOKIE);
What you end up with is an array that contains all the data from the respective requests. The just go ahead and replace $_REQUEST with $code_array inside the function, i.e
\\replace $_REQUEST with $code_array;
if (isset($code_array['code'])) {
if ($this->state !== null &&
isset($code_array['state']) &&
$this->state === $code_array['state']) { //...and so on for the rest
This should do the job nicely (hopefully).
OPTIONAL - Extending your Access Token Lifetime
This is optional, but I included it anyway. Most New Apps will already have long lived Access Tokens, but just in case, you can use the $facebook->setExtendedAccessToken(); method to transform your existing access token.
Note: You have to call $facebook->setExtendedAccessToken(); before you actually get your access token with the getAccessToken() method.
Now, using your code you will have
$user = $facebook->getUser();
if($user) {
try {
// Just to be sure, add access token to each request
$facebook->setExtendedAccessToken();
$access_token = $facebook->getAccessToken();
// Fetch user details
$user = $facebook->api('/me?access_token='.$access_token);
}
//and so on..
CONCLUSION
Breaking $_REQUEST into $_GET,$_POST & $_COOKIE (Even though it includes all three by default) seems to ensure we can fetch the cookie that was set by the SDK(s) without much trouble. I say seems because heck, I'm not really 100% sure myself.
I Used the above methods to get it working in my case, so I'm hoping to share some knowledge, as I've been losing far too much sleep over this problem, and couldn't find a viable solution.
Hope this helps!
EDIT: I forgot to mention, changing the API request from
$user_profile = $facebook->api('/me');
to
$user_profile = $facebook->api('/'.$user.'?access_token='.$access_token);
was something I also did, and it made a difference. :)

Maybe because the Facebook PHP SDK is not ajax and we are using PHP pages and our servers load faster than the authentication process from Facebook to read back a valid session. what the Facebook PHP SDK requires is something to refresh the page on session validation from our apps, this should be built in to the Facebook Javascript SDK but it looks like it isn't.

Related

Facebook php api giving access to users with invalid tokens

I am using the facebook php api to control the access to some parts of my webapp. Basically I am just checking if the user is logged into facebook and the user authorize the app (basic permission) every time the page is load and then printing things according to the state.
Something like, if($check_user_lo_npe) { echo 'Welcome!'; }, simple as that. Well, everything is working fine, until I realize that if the user deletes the app from their users settings in facebook, which means the token gets invalidated, I am still getting a true response from the function check_user_lo_npe even if I know the token is invalid because as I said, the user deleted the app. This is how I am checking the permissions:
function check_user_lo_npe() {
global $facebook;
global $data;
$fb_user_id = $facebook->getUser();
if ($fb_user_id) {
try {
if(!isset($_SESSION['fb_user_profile'])) {
$_SESSION['fb_user_profile'] = $facebook->api('/me');
$temparray = $facebook->api('/me/friends');
$_SESSION['fb_user_friends'] = count($temparray[data]);
}
$data->reg_user($_SESSION['fb_user_profile'],$_SESSION['fb_user_friends']);
return array(true,'');
} catch (FacebookApiException $e) {
$fb_user_id = NULL;
return array(false,$e->getMessage());
}
} else {
return array(false,'');
}
}
I need to realize when the user deletes the app so I can send them to the login screen again, the function is supposed to detect when there is an exception, but somehow I am not getting any... why?
Those $_SESSION variables are set by your app, not by the Facebook SDK right?
Without attempting to access the Facebook session you can't be sure if that session is still active/
If you need to check on each page whether there's still an active Facebook session or not, look at FB.GetLoginStatus() in the Javascript SDK, or make an API call to (for example) /me/permissions to check your access token is still valid
That said, it may be as easy to just have an exception handler which detects when an attempt to access Facebook's API fails, and have it send the user through the authentication flow at that point.
Your if ($fb_user_id) line is probably evaluating to false, which causes you to return array(false,''); in your else statement, never triggering an exception.
If you did get past the ID check, it looks like you are putting data into $_SESSION before they delete the app, and then not re-checking it. Once you have it in the $_SESSION, if you don't go back to Facebook to verify, there is no reason an exception would be thrown.

How to check if a user is logged in to facebook

I am totally new to facebook api and I wanted to ask , whats the easiest and fastest way to know if a person is logged in to facebook.
One solution that I tought of is to send a javascript or php request and see if i get some status code that tells me whether the person is logged in or not (say if it returns 404, then that means he isnt logged in).
update:
I found this easy "hack":
function logged() {
alert('logged');
}
function notlogged() {
alert('not logged');
}
</script>
<script src="http://www.facebook.com/ajax/composer/attachment/question/question.php" onload="logged()" onerror="notlogged()">
But it doesnt work... however, thats the type of code that i am looking for..code that would send a request and if fails, it will throw an error
**update**
I dont want to trigger any suspicion from the user that I am checking if he is logged in. So if there is a use of app_id, then I would think that I need the users permission to use my app..that is a burden cause I will have to take another authentication step.
I cant have the user know that he is being authenticated in any way regarding facebook
If I am reading your code correctly, only if no session is returned do you do the redirect? According to comments in Facebook's example: http://github.com/facebook/php-sdk/blob/master/examples/example.php (great place to this info huh?), even if you get a session back, you can't assume it's still valid. Only trying an API call that requires a logged in user will you know for sure. This is the best way I've seen to reliably determine login/logout status.
if ($session) {
try {
$me = $facebook->api('/me');
if ($me) {
//User is logged in
}
} catch (FacebookApiException $e) {
//User is not logged in
}
}
try This, Hope this will help
include 'facebook.php';
$facebook = new Facebook(array(
'appId' => $app_id, // your application id
'secret' => $app_secret, // your application secret
'cookie' => false,
));
$user = $facebook->getUser();
$loginUrl = $facebook->getLoginUrl(
array(
'scope' => '// put your permission'
)
);
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$permissions = $facebook->api('/me/permissions');
} catch (FacebookApiException $e) {
$user = null;
}
}
if (!$user) {
echo "<script type='text/javascript'>top.location.href = '$loginUrl';</script>";
}
If you have a facebook "tab" then limited user information is provided to you as part of the signed_request. And for a facebook tab, you need to create an app.
Otherwise, without an App ID and alerting the user YOU CANNOT DO IT.
There have been hacks in the past, some of the cleverer ones have been to put up comment boxes and measure the hieght of the containing DIV (they used to be larger if logged in) or to include the facebooks FBML tabs to show a log in button (log in was wider) but theses were all stamped out as they were discovered. The same probably goes for the link you tried in your question.
Facebook, for all the debate on rpivacy, won't knowlingly leak information - until you get an app id, ask the user then you can get nearly everything...
Check this topic: https://stackoverflow.com/a/10698594/1789650
This should answer your question. You have to load the javascript SDK to get it to work correctly.

$facebook -> getUser() returns wrong value?

The question is the same as title. I'm using the latest php-sdk (v3.1.1) to operate server-side authentication flow.
I have 2 tabs in Chrome, one is my Facebook page and the other is php test page. These 2 problems happen many times:
$facebook->getUser() still returns 0 even when I logged in.
$facebook->getUser() still returns an ID even when I logged out.
I have to do a work-around of this: try initiating a graph API request with provided access_token, and check if $response->error->type == "OAuthException" to ensure there's an active session or not.
Is there any way to use $facebook->getUser() "stably"? I've searched a lot through SO but not found best answer for php-sdk 3.1.1 yet.
Highly appreciate any helps. Thanks.
Login.
As per documentation example of FB SDK, getUser() returns userId even when you're logged out, but have cookies associated with FB account.
To detect is user logged in you should use
$user = $facebook->getUser();
//Check Access token
if ($user) {
try {
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
$user = null;
}
}
if ($user) {
//logged-in
} else {
//not logged-in
}
To login in your app make user logs in in your app, not on neighbouring tab, by following this url (make sure that you're passing the scope based on intended actions performed by your app):
$loginUrl = $facebook->getLoginUrl(
'scope' => ...
);
Logout. Seems that your PHP server is storing some values of access tokens per session, so even when you're logged out in your browser, your server still have these tokens valid. Actually, I don't know, is it bug or feature, but they're not destroyed by Facebook after user logout.
To destroy these tokens I'm using these:
$facebook->destroySession();
I'm calling it every time when user logs-out by $facebook->getLogoutUrl();

Facebook connect is very slow, can I use AJAX?

I'm implementing the facebook php sdk and using it for user login/connect.
Everything works as expected, however, at the top of each page, I need to call
$facebook->api('/me') to determine if the user is logged in or not..
This call is very slow, sometimes, taking up to 2 seconds to return.
So, any interaction by the user, always has a 1-2 sec delay before any page loads..
I suspect, it's because, the $facebook->api('/me') call is using httpS ..
Any suggestions....
$facebook = new Facebook(array( 'appId' => 'xxxxxxxxxxxxxxx', 'secret' => 'xxxxxxxxxxxxxxxxx',));
$user = $facebook->getUser();
if ($user)
{
try { $user_profile = $facebook->api('/me','GET'); }
catch (FacebookApiException $e) { error_log($e); $user = null; }
}
$login_parms = array('scope' => 'user_birthday', 'redirect_uri' => 'http://xxx.com/login');
$login_link = $facebook->getLoginUrl($login_parms);
if($user)
{
/* logged in */
}
else
{
/* not */
}
You really shouldn't perform the Facebook API request on each page load. Only do it once when the user logs in. Then you can store the "logged in" flag in the session (or a signed cookie).
If you need to store e.g. some of the user's facebook profile information, also put it in the session or your database.
Add some spinning wheel where login form is, then call ajax on document ready to your php script, script returns false or loged in user data (or more data if you need - redirect url) and then depending on result show form to login or display currently loged in user.
What i mean Javascript will handle all logic depending on what is returned from server, redirects, change UI etc.
Another way is to cache (session with expiration) first call to facebook if user is loged in remember it. And check if that Session variable is present and not yet expired. Only call again when doing some sensitive tasks or get expired.
If you do not need to get "fresh" values from $facebook->api("/me").
Then I would suggest you cache the response, if you use any PHP-framework (eg. Zend, Yii, Codeigniter) this should be really straight forward.
If you're not using a PHP-framework i suggest you still look into the excellent ZF documentation for their cache solution.
Zend Framework - Cache
If you, however, need fresh values each load you can make a simple page that only returns the $facebook->api("/me") part and returns it as bare HTML. Then simply keep a or similar that recieves the response when it's finished.
An easy solution would be using jQuery and just write:
$("#div-id").load("/page-that-returns-facebook-api-me-result");

Facebook API - Session still exists after user logout

I am using Facebook php-sdk in my iframe facebook app to get user login status.
Right after I sign out using facebook Account > Log out link, the session is not destroyed yet. I must wait a few minutes before old session expires, then my app will again get the correct login status.
I expect the facebook to kill itself and the session when user signs out. How do I manually kill the session?
Here is my code:
$initParams = array(
'appId' => $conf['app_id'],
'secret' => $conf['secret_api_key'],
'cookie' => TRUE,
);
$fb = new Facebook($initParams);
$fb->getSession(); // will return a session object eventhough user signed out!
SOLVED:
calling $fb->api('/me') will destroy the session if user has previously logged out.
I've changed my code as following:
if ($session)
{
try
{
$fbuid = $fb->getUser();
$me = $fb->api('/me');
}
catch(FacebookApiException $e){}
}
If the API call is unsuccessful, $session will be set to NULL. Very weird behavior, I don't explain everything that is going on here but it solved my problem of having residual session object not being updated via getSession() method.
I'm using $fb->getUser() and what I did was almost identical with yours.
if ($fb->getUser())
{
try
{
$me = $fb->api('/me');
}
catch(FacebookApiException $e){
**$fb->destroySession();**
}
}
I found that using only API to check whether FB is logged out or not sometimes is inconsistent, but with destroySession(), the session will surely be destroyed.
if you are using the javascript FB.INIT calls on the login page, then set status to false from true.
details about the status attribute :
http://developers.facebook.com/docs/reference/javascript/FB.init/
Try finding the formatData function somewhere at LoginWindow (AS3) and find this line:
vars.redirect_uri = FacebookURLDefaults.LOGIN_SUCCESS_URL
Change the value for http://www.facebook.com/ and logout from that html page when logged in.
This is a temporary solution to logout if you are developer, not the end user.
Facebook should disassociate the session from the account that the session belonged to. You can use Facebook::getUser() to check whether this was done:
if ($fb->getUser() === null) {
// User logged out
} else {
// User logged in
}
Try $facebook->setSession(null) or using javascript Logout
Logout does not work any way you do.
Try posting this link in your browser, after you log in to facebook.
https://www.facebook.com/logout.php
What happen? it takes you to your facebook. No logout at all.
What ever you do, check the function (depends on your API) handleLogout and check the output. In my case, it returns the entire facebook html page.
The only way I've managed to solve this problem was by clearing the session using the signed request to check the user id:
$facebook = Membership::getFacebookApp();
$signed_request = $facebook->getSignedRequest();
if(isset($_SESSION['facebook_id']) && $signed_request['user_id'] != (int)$_SESSION['facebook_id']){
$_SESSION = array();
}

Categories