Loose req.session when trying to get more FB privileges via everyauth - facebook

I've been doing user authentication with everyauth and Facebook and all works well. Now, I want to integrate an ability to post to Facebook. Since my app asks only for email scope when users first login, I'll need to get a larger FB scope, and am trying to follow the FB guidelines and only ask for this additional scope when I need it.
I added the following code to my everyauth configuration as per the docs:
everyauth
.facebook
.appId(conf.fb.appId)
.appSecret(conf.fb.appSecret)
//TODO add custom redirect for when authentication is not approved
.scope(function (req, res) {
console.log('Setting FB scope');
console.log('Session: ' + util.inspect(req.session));
var session = req.session;
switch (session.userPhase) {
case 'share-media':
return 'email,user_status';
default:
return 'email';
}
})
All is well when an unauthenticated user logs into the application. The problem is that when I want to "up the ante" on FB scope, which I do by setting req.session.userPhase to 'share-media', and then present a link to /auth/facebook to confirm they want to allow posting to FB. When this happens, I get an error that req.session is undefined from the above code (all of req is undefined).
I assume this is since a previously logged-in user is essentially re-authenticating, but isn't that how I would get more scope from Facebook? Am I going about this the wrong way?
Thanks!!!

Related

passport-remember-me functionality not working in my sails js application

I’m struggling with passport-remember-me functionality in my app since a few days but didn’t find a way to make it a successful implementation. I’ve followed every instructions given in the documentation and followed various examples given by Jared Hanson. However, it doesn’t work.
The code seems to be right, as it sets the cookie when a user logs in to my application. It also consumes the token correctly when session gets expired and re-issues a new token. After reissuance of token, it updates the cookie with that token. So everything seems correct though when session gets expired, the user gets redirected to the login page.
Can anybody please give some pointers on what could be the issue ? Do I need to check cookie in my sessionAuth.js where I’m checking whether the user is authenticated. The code is as below.
module.exports = function(req, res, next) {
// User is allowed, proceed to the next policy,
// or if this is the last policy, the controller
if (req.isAuthenticated()) {
return next();
}
console.log(" not authenticated in ");
// User is not allowed
// (default res.forbidden() behavior can be overridden in `config/403.js`)
req.flash('message', 'The user session has expired. Please login!')
return res.redirect('/login');
};

How to authenticate Facebook User after receiving response.status === 'connected'?

Perhaps I am going about this the wrong way but I have a website that allows facebook login.
If the user has already registered on my website
and is logged into facebook but not logged into my site
when visiting the login page i check for their facebook login status and get response.status === 'connected' via-
FB.Event.subscribe('auth.authResponseChange', function (response)
{
if (response.status === 'connected')
{
var s = JSON.stringify(response.authResponse);
LogMeIn(s, function(response)
{
HandleAjaxError(response, function(msg)
{
window.location = '/_/';
});
});
}
}
I then want to pass their authResponse object to the server and confirm that this userid works with this token before I log them in as this user
I have read to simply grab the json contents of -
https://graph.facebook.com/{userID}?access_token={accessToken}
and if it does not return an error then it is good! But when testing this method I noticed that the same access_token worked for two different user ids (meaning it did not return an error for the userid that was not logged in on my computer). Instead it returned the facebook user object with name , location etc.
This really surprised me, as I expected the access_token to work only with a single user id.
In an effort to prevent someone from simply changing the user id before continuing the script I need to authenticate via server side. What is a way to accomplish this?
Proof, go to these links to see profile information
My profile-
https://graph.facebook.com/1233822590?access_token=CAACCBJJZBgjABAOGmvmsou8gMYGulLHTgAr5ZCHZAU7pKEp0cMAeX8r4qHLpiVuZCOT1v0ulMZAxX5YfLJkcZBr9l6qJQoPxWS5Fs5ndohDnH6ZAPPfZCZCTQtwWgAZAg6I1PAOIpdtCc0OUaMmBZAvGiMm9gQhmNXRbocZD
Another userid with same access_token-
https://graph.facebook.com/100000116781159?access_token=CAACCBJJZBgjABAOGmvmsou8gMYGulLHTgAr5ZCHZAU7pKEp0cMAeX8r4qHLpiVuZCOT1v0ulMZAxX5YfLJkcZBr9l6qJQoPxWS5Fs5ndohDnH6ZAPPfZCZCTQtwWgAZAg6I1PAOIpdtCc0OUaMmBZAvGiMm9gQhmNXRbocZD
Nothing to be surprised. You can fetch the basic details of any user of the facebook using the access token of any user of the facebook.. So this isnt really good way to validate the token. Moreover, that confirmation of token part isnt required.
If you want the authorization through server side go through.this link

Facebook PHP SDK usage stand alone - how do the Facebook sessions/cookies work?

I'm utilizing the Facebook PHP SDK on its own. I do not want to use the JS SDK at all.
Because getUser(); from the SDK can return a user id even if the user is not logged in, I have opted for using a try/catch statement to check if the user is logged in.
try
{
$me = $CI->facebook->api('/me');
$CI->our_fb['is_fb']='YES';
echo "hello";
}
catch(FacebookApiException $e)
{
echo "catch";
}
This statement is included in the global include file of all of my files (for simplicity).
So, depending on the situation, I generate a Facebook login URL. The expected functionality is that the user logins to Facebook, authorises the app, is returned to the redirect URI set in the login URL at which point the try statement will execute, and $CI->our_fb['is_fb'] will be set.
This is however not happening.
If the user is already logged into Facebook and the app is authorised, it works perfectly. SUCCESS
If the user is not logged into Facebook, once redirected the variable is not set. FAILURE
If the user is logged in but the app is NOT authorised after redirect the variable is not set. FAILURE.
In the latter two cases if you simply refresh the page, the variable is set - SUCCESS. Refreshing the page is however unnecessary/pointless extra effort.
My problem is that if you need to login to FB/or authorise the app e.g the first time you login with FB, you have an additional unneeded refresh, and I don't know why.
I suspect it is something to do with the cookie/session? Which saves the access token that I assume is returned/passed to the SDK automatically not being set at the same time?
Anyone got any ideas?
If you're having an app on facebook (tab or canvas). PHP SDK only get the User ID on initial loading of a page because a signed_request is sent with the request to your app.
But, when the app refreshes, the signed_request is lost (as it's facebook who send it).
So, in this case, you can append the signed_request to every URLs your use in your app - but that's really not optimal as the signed_request won't be regenarated - neither refreshed.
Your only real option is to rely on the JS SDK to set cookie correctly and allow getUser to work as expected. This is required because you're considered as a third-party app in Facebook (being in an iframe) and most browser will block you from setting cookies - so you need a work around handled by the JS SDK for you. You can search for cross-domain cookies or third-party cookie for explanation about the workarounds, but these workaround only work via JS scripting and iframe management.
Also, be sure to setup the JS SDK correctly: channel file, cookie allowed, and send P3P headers (for IE).
You can also check this related question: A proper approach to FB auth
About website, the same mostly stays (but you have no signed_request). At this point, seriously consider using the JS SDK as it's way easier. Or else, you can make sure your app flow follow these guidelines: https://developers.facebook.com/docs/concepts/login/login-architecture/
The way I am seeing this is, you are trying to avoid that refresh if the user is not logged in and precedes to log in after the page has initially loaded.
So what you can do is make an ajax request to another page on your site, say for example id.php, which just loads the php sdk and echo $userid; and then you can grab the user id after login without the refresh.
Basically the cookie is used to save the signed request and session is used to save 'state', 'code', 'access_token', 'user_id'. If the above are present PHP SDK uses them, no matter if they are valid or not.
I think your problem lies in the CODE sent by facebook. Specifically these lines in base_facebook.php:
if ($code && $code != $this->getPersistentData('code')) {
$access_token = $this->getAccessTokenFromCode($code);
...
protected function getAccessTokenFromCode($code, $redirect_uri = null) {
if (empty($code)) {
return false;
}
if ($redirect_uri === null) {
$redirect_uri = $this->getCurrentUrl();
}
...
Because CODE is issued for specific url sometimes there is such situation: Visitor arrives on www.example.com. He givies permissions and is redirected to example.com/login. But the code is not valid there, so the getUserAccessToken returns false. When you refresh the page you get same urls and everything's fine.
You're on the right track of not using getUser() because as I wrote above it's taken from the session if available.

Graph Request Only Works With My Facebook Account

I have a web page which asks the user to log in and then proceeds to get JSon via Graph for a particular Facebook group. It builds the Uri dynamically by taking the access_token that is returned after login. It works fine when I do this, but if I try to log in with a different account, no data for the feed is returned.
One hint in this problem is when the facebook dialog screen appears, it only asks for my username/password. It doesn't ask go to the usual screen where Facebook asks for you to give permissions for "Basic Information" etc. It's just a username/password screen and then I go straight in.
This is the login code:
function login()
{
FB.login(function (response)
{
if (response.authResponse)
{
// connected
var authResponse = response.authResponse;
access_token = authResponse.accessToken;
refresh();
} else
{
// cancelled
}
});
}
One hint in this problem is when the facebook dialog screen appears,
it only asks for my username/password. It doesn't ask go to the usual
screen where Facebook asks for you to give permissions for "Basic
Information" etc. It's just a username/password screen and then I go
straight in.
This is because you've already authorized the app, so once you login it will take you straight to the app.
It works fine when I do this, but if I try to log in with a different
account, no data for the feed is returned.
Well the limited view of code you posted is fine, so something else is the problem. First debug step is to get the access token for that different account, and check the debugger to see if its tied to the appropriate user and scope.

Extend auth token without refreshing the page

Users want to use my facebook app for many hours without refreshing the browser.
But token expires in 2 hours. Now I ask users to refresh the page but that's annoying.
I don't want to ask offline access permissions because it will scare some users.
The best solution will be somehow "relogin" and get new token without refreshing the page.
Is it possible?
I would subscribe to the expiry trigger (I think this is authResponseChange), then automate another login check. It won't be a perfect solution as it could trigger a pop up (if they have logged out for example) automatically, which a lot of browsers may block. You could instead, when the token expires, check if they will need to complete a pop up, and display a notification on your page somewhere saying 'Facebook needs your attention to continue', then only launch the pop up from their response, which would stop the pop up being blocked.
FB.Event.subscribe('auth.authResponseChange', function(response) {
// do something with response
FB.login(){
// refresh their session - or use JS to display a notification they can
// click to prevent pop up issues
}
});
An algorithm to workout on this
Ask for permission from the user
Save the token
Periodically check for an access token is near to expire or not
If its in verse of expiry, embed some dummy iframe, which redirects to the facebook homepage. - Extend auth token without refreshing the page
This should refresh the token. You might need to generate another token or continue with the same. Whatever be required, can be done without refreshing the page.
Have you thought of using ajax? After two hours you will check, if user is still active. If so, you send axax request to URL, where his session details will be updated. example:
$(document).ready(function(){
setInterval('update_session()', 5500000);
})
update_session(){
$.post({
URL: ..., // script to update session on server
data:{ /* username, password */ },
})
}
and the server-side just takes username and password from post or and runs relogin.
Try acquiring tokens with the offline_access permission.
I presume, guess this is not possible,FB architecture would not allow it. And why is offline_access such a problem!!!!!!...anyway offline_access is the best optimal solution I guess....
Unfortunately I believe this is impossible by design (if you mean for it to happen without user intervention). If the user is still logged in to Facebook you can redirect the top-level page to Facebook and it will bounce you right back with a new code (as it sounds like you are doing already), but that is only possible because of the Facebook cookie that it can check. If you try to do anything from your server, it will be rejected because that cookie will not accompany the request. Same goes for trying to make a call to facebook from javascript -- since your code is running in a different domain, the cookie will not accompany the call and Facebook will reject it. The only way that Facebook can even know who the user is, and that they are still logged in, is to see that cookie. And the only way that can happen is if the browser itself is redirected to the facebook.com domain.
It's worth mentioning also that Facebook has blocked the only logical workaround, i.e. loading the oauth url in an iframe. If you try it you will see that they detect the page is being loaded in an iframe and output a page with a link on it which does a top-level redirect to break out of the frame. So not only does this approach not work, it's clear that Facebook has specifically made it impossible as part of their architecture.
Edit: If what you mean to do is not avoid the refresh altogether but just have it happen automatically when a new token is needed, you can do something like this:
$status=0;
$data=#file_get_contents("https://graph.facebook.com/me?access_token=$token");
foreach ($http_response_header as $rh) if (substr($rh, 0, 4)=='HTTP') list(,$status,)=explode(' ', $rh, 3);
if ($status==200)
{
//token is good, proceed
}
else
{
//token is expired, get new one
$fburl="http://www.facebook.com/dialog/oauth?client_id=APP_ID&redirect_uri=".urlencode('http://apps.facebook.com/yourapp/thispage.php');
echo "<html>\n<body>\n<script>top.location='$fburl';</script>\n</body>\n</html>\n";
exit;
}
This is assuming you have something before this code that will process a signed_request parameter if it is present and assign a value to $token (either explicit code of your own or the appropriate SDK entries). The shown code can then be used anywhere you need to check if $token is still valid before proceeding.
If you get the access_token without specifying any expiry to them they will not expire ..
atleast not till the time user either changes his Fb credentials or de registers your application ..
I presume you are using the iframe signed_request parameter to get your access token. One method of achieving what you require is to use the oAuth 2.0 method of aquiring an access token. This is more prolonged in the first instance; your server and Facebook's have to exchange credentials which can be slow, but it means that you will be given a code that can be exchanged for an access token regularly, meaning your server can maintain the session periodically (probably from an ajax call from the client). You would then pass this new access_token to the client, and use it in your dialog call for your requests (gifts).
Hope that helps.
Spabby
Have a look at https://developers.facebook.com/docs/offline-access-deprecation/#extend_token
basically you extend the token with
https://graph.facebook.com/oauth/access_token?
client_id=APP_ID&
client_secret=APP_SECRET&
grant_type=fb_exchange_token&
fb_exchange_token=EXISTING_ACCESS_TOKEN
that will give you new token with new expiry time (it should be 60d but I'm noticing similar bug like described here https://developers.facebook.com/bugs/347831145255847/?browse=search_4f5b6e51b18170786854060 )