Logging out of JS SDK doesn't log out of PHP SDK - php

I have a website that is using both the PHP SDK and JS SDK.
After updating to OAuth in both, I've noticed that logging out of JS doesn't actually log the user out of PHP.
It seems like the general solution is to make a call for '/me' and then, if that errors, assume the user has logged out. However, I don't need to call /me on every page render, I just want to know whether the user is signed in without the performance hit of a FB API call on every render.
Is there a way for the PHP SDK to be informed of a logout that happened via the JS SDK?
Some things I've tried:
Comment out the contents of setPersistentData in Facebook.php
Manually delete the fbsr_::appid:: cookie
Thanks!

setcookie(session_name(), '', time()-42000, '/');
unset($_SESSION);

get the user access token from facebook library
$access_token = $this->facebook->getAccessToken();
and then use this code in the logout function
if ($this->facebook_user)
{
$logoutUrl = $this->facebook->getLogoutUrl()."&access_token=".$access_token;
redirect($logoutUrl);
}
And make some changes in facebook library file.
public function getLogoutUrl($params=array()) {
return $this->getUrl(
'www',
'logout.php',
array_merge(array(
'next' => $this->getCurrentUrl(),
), $params)
);
}

Related

Facebook PHP SDK session lost, needs JS SDK refresh

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.

Facebook logout does not remove the user completerly in my app

I have the facebook_sdk that I am using to authenticate facebook users on my app. Everything is fine but when the user is logged out for facebook he is logged out but his information still is on my application . So I want to kill session by the time he logged out. So Can you help me this. I have seen many posts related But didn't find correct answer to my case.
So I want to kill session by the time he logged out.
Give a redirect_uri parameter when creating your logout URL, and put a script there that calls session_destroy().
Facebook SDK does not kill session in my application, so I edited the method getLogoutUrl in base_facebook.php and now It is fine.
public function getLogoutUrl($params=array()) {
session_destroy();
return $this->getUrl(
'www',
'logout.php',
array_merge(array(
'next' => $this->getCurrentUrl(),
'access_token' => $this->getUserAccessToken(),
), $params)
);
}

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");

OAuthException on Facebook Graph API Logout, Works After Refresh

I am using a modified version php-sdk version 3.0.0 sample code at github.com/facebook within the CodeIgniter framework as a helper.
My problem is just as the title says: When I click the logout anchor (provided by $Facebook->getLogoutUrl()) I am redirected back to the same page and receive an OAuthException:
Fatal error: Uncaught OAuthException: Error validating access token: The session is invalid because the user logged out. thrown in [...]/base_facebook.php on line 959
When I refresh, it loads the "login" anchor like it normally would. What is happening on that refresh/post-back that isn't happening on that initial redirect?
I realize this is limited information but due to the problem I think it may be a simple fix.
EDIT: This post seems to be relevant: http://forum.developers.facebook.net/viewtopic.php?id=71219
Specifically this line:
setcookie('fbs_'.$facebook->getAppId(), '', time()-100, '/', '.domain.com');
However, I am not sure how to implement this and still use $facebook->getLogoutUrl();.
Thanks in advance and just let me know if more information is necessary.
I was having the same problem and nearly pulling my hair out. However, after some research, it appears the problem is an offending cookie. This line on logout should fix it:
setcookie('fbs_'.$facebook->getAppId(), '', time()-100, '/', '.domain.com');
Ensure to add the '.' before the domain name if subdomains are being used.
I hope this helps!
As suggested, I tried:
setcookie('fbs_'.$facebook->getAppId(), '', time()-100, '/', '.domain.com');
This didn't work. What I did, was to just copy from the fb example code:
// Get User ID
$user = $facebook->getUser();
// We may or may not have this data based on whether the user is logged in.
//
// If we have a $user id here, it means we know the user is logged into
// Facebook, but we don't know if the access token is valid. An access
// token is invalid if the user logged out of Facebook.
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
// Login or logout url will be needed depending on current user state.
if ($user) {
$logoutUrl = $facebook->getLogoutUrl();
} else {
$loginUrl = $facebook->getLoginUrl();
}
The middle part, with if try get user_profile, is a test to get the user profile, and if it fails the userid will be unset. This will make the last part with getLoginUrl() and getLogoutUrl() correct.
I do believe setting the cookie is more correct, than to try a request and see if it fails... but since the setcookie didn't work, I didn't have a choice :(
Stupid facebook that returns a token with this $user = $facebook->getUser();, when the user actually is logged out.
Hope this helps those who is in need.
From the looks of your error it would appear your website is still trying to connect to Facebook using the SDK. When you run the logout function provided by Facebook make sure to clear whatever sessions or storage you have that triggers calls to Facebook.
It's likely that they aren't being cleared before you attempt your Facebook logout, and this is why it still thinks you have a connection but then works fine on refresh.
What I ended up doing was this:
$facebook->getLogoutUrl(array('next' => site_url('logout')));
Then in the 'logout' controller:
$_SESSION = array();
$this->load->view('myoriginalview');
On logout, the facebook logout url's query string redirect_uri value is set to redirect to the 'logout' controller which then clears the session and loads the view on which the logout button existed in the first place. Everything functions fine. Now I just have to figure out how to handle an expired session as opposed to a logged out user -_-
EDIT:
What I've done now is invalidate the cookie in the proper manner as described on the facebook developers forum. I really wish their documentation was better and described this for their PHP SDK.

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