knpuniversity oauth2client expected state is null often - facebook

vendor/knpuniversity/oauth2-client-bundle/src/Client/OAuth2Client.php:
When I logout user and try to login with facebook again, often I get this exception - InvalidStateException. "User see Invalid state parameter passed in callback URL." Thats because there is no data in session. But why that can happen?
Using this bundle:
https://github.com/knpuniversity/oauth2-client-bundle
This is called from my facebook authenticator class:
public function getCredentials(Request $request)
{
// this method is only called if supports() returns true
return $this->fetchAccessToken($this->getFacebookClient());
}
Also noticed if I try again to login with facebook after this exception, then it logs in succesfully. But later noticed this is also not always the case.
I am thinking there is soemthing to do with race condition somewhere, because when I use xdebug and code stops at breakpoinst, it often workse ok.

The problem was chrome sending 2 requests because of prefetching.
https://www.keycdn.com/support/prefetching
When I enter url in address bar (for testing I had not made facebook button yet) chrome instantly loads it. Then I press enter and it loads it again. And things start happing what is unexpected when there are 2 requests to login with facebook.
Tested on firefox, there is no such problem. When I have made link to login to facebook and so I dont have to type in address bar, it also does not make prefetch and problem is gone on chrome also.

Related

Unity Facebook SDK: FB.IsLoggedIn / FB.ShareLink issue

I'm trying to create my mobile app user to share my Facebook page and if they do, I give them an in-game item. I'm using the example code provided by Facebook here: https://developers.facebook.com/docs/unity/examples
The first issue is that FB.ShareLink doesn't comeback negative if the user cancels the sharing action. From what I've read, that's on purpose and it only works correctly if the user is logged in and my app is authorized. I tested it and that's true, if I use the login code to first login, it comes back as positive or negative correctly.
The second issue that I'm having though is that FB.IsLoggedIn never comes back negative and I'm not sure how to properly check this because even though it comes back as true, my app is note authorized and FB.ShareLink doesn't return negative when canceled. I start the Login issue and then I press the back arrow to cancel it but FB.IsLoggedIn still comes back as true.
How can I just check if the app is authorized? I'm guessing that's all I need to check before running the FB.ShareLink code.
Any ideas?
Thanks!
First, we try to login asking for the user's e-mail address.
public void LogIntoFacebook() {
List<string> perms = new List<string>() { "email" };
FB.LogInWithReadPermissions(perms, OnLogin);
}
Then you can check to see if you got the e-mail address permission using
AccessToken token = AccessToken.CurrentAccessToken;
if (token.Permissions.Contains("email")) { // do something }
If you do, then you move forward with the Facebook share.

Azure mobile facebook authentication with iPhone HTML5 in app (full screen) mode

I have an HTML5 application that uses Azure mobile services authentication to login (straight from the example code...provided below). It works fine in all desktop browsers and iPhone 5 in Safari. But from app / full screen mode, it does nothing (doesn't ask for permission to show a popup window like it does in safari and no popup windows shows up) and I can wait forever and nothing happens. If I invoke it a second time, it gives an error saying "Error: Unexpected failure"...perhaps because the 1st attempt is still running? Any help/insight is appreciated.
client.login ("facebook").done(function (results) {
alert("You are now logged in as: " + results.userId);
}, function (err) {
alert("Error: " + err);
});
edited update with more info and 2 potential ideas*
I did some more research and found a site that uses an approach that overcomes this problem and also solves two other side effects with the current Azure mobile approach to authentication. I think the Azure mobile team might be looking to do something similar because there are some hints of other authentication options in the code (although difficult to read and be sure because the minimized code is obsfucated). It might be just a matter of activating these in the code...
The "solution":
Go to http://m.bcwars.com/ and click on the Facebook login. You'll see it works perfectly in iPhone Safari in "app mode" becuase instead of doing a popup, it simply stays in the current browser window.
This approach solves two other problems with the current Azure mobile approach. First, the popup gets interpreted by most browsers as a potential ad and is either blocked automatically (desktop Chrome) ... and the user doesn't know why it's not working...or gives a warning which the user has to approve (iPhone Safari in "browser mode") which is a hassle. And if the user has a popup blocker, it gets more difficult and even more potential for the user not getting it to work properly. The bcwars.com method doesn't have this problem.
Second, in iPhone Safari, when the popup window auto closes, the original page doesn't get focus if there are other browser windows open in Safari. Instead, it's in the smaller/slide mode so they can choose which one to show. If this happens, the user has to go through one more sttep...click on the browser window to activate it and give it focus..again more of a pain and more potential for them to mess up and not do it correctly and need help. The m.bcwars.com doesn't have this problem.
Azure options:
Looking at the Azure mobile code it looks like may already have the solution. I can't read it easliy becuase it's minified/obsfucated, but it seems to have 4 options (including iFrame, etc.) for invoking the authentication, and only 1 (the "less ideal one" of a popup) is being used. An easy solution would be to set a property to allow one of the alternate authentications to work. But I can't read it well enough to figure it out. Another would be to hack the code (temporarily until a fix is put up by Microsoft).
Could I get some help there perhaps?
You can implement an authentication flow with Facebook that doesn't use a popup. The basic idea is to use the 'Web Flow' for doing the login, and once the window return from the login, use the access token to login the user in to Azure Mobile Services.
The Facebook documentation for doing this is here:
https://developers.facebook.com/docs/facebook-login/login-flow-for-web-no-jssdk/#step2
Some code samples to make it easier for you.
You would start by something like this:
(Remember to replace YOUR_APP_ID and YOUR_URL with something relevant to your site.
function logIn() {
window.location.replace('https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=http%3A%2F%2FYOUR_URL&response_type=token')
}
This redirects the window to the Facebook page for the user to log in and authorize your app. When the user is done, Facebook will redirect the user back to YOUR_URL given above.
There you can handle the redirect and do the Mobile Services Login with something like this:
function handleLoginResponse() {
var frag = $.deparam.fragment();
if (frag.hasOwnProperty("access_token")) {
client.login("facebook", { access_token: frag.access_token }).then(function () {
// you're logged in
}, function (error) {
alert(error);
});
}
}
In here you parse the access token you get as a URL fragment and pass it as argument to the login call you make to Azure Mobile Services.
This code depends on the jquery BBQ plugin to handle the URL fragment easily.
Hope this solves your problem!

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.

Facebook redirect after login

I have read a number of questions and answers, including this one on StackOverflow and none works. My question to all responses I have seen are 'does it work in Safari?'.
I am trying to get this to work with Safari. It works on Chrome and Firefox fine. But in Safari the login screen just freezes and I get the "Unsafe JavaScript attempt to access frame with URL" log message.
I have a canvas app. I want to log the user in and redirect them to a page once they have logged in. I am trying to redirect directly after login. I have tried
setting window.top.location to a facebook url (with some data passed to a signed request as the all_data argument)
setting window.location to a URL with the same domain as my app.
subscribing to the auth.login event and putting the redirect there
putting the redirect in the callback to login
None of these works for Safari. I'm starting to think that there's no way to do it.
function doSomething()
{
FB.login(
function(loginResponse)
{
if (loginResponse.authResponse)
{
window.top.location = "my url"
}
},
{
scope:"some,scope"
}
);
}
}
In response to Nitzan Tomer, here is the equivalent code which doesn't work with Safari but does work with others:
function myThing()
{
FB.login(function(loginResponse)
{
if (loginResponse.authResponse)
{
FB.api('/me', function(response)
{
window.location = "http://my_app.com?x=" + response.xyz;
});
}
},
{
scope:"scopes"
}
);
}
This is not much of a solution to your problem, but more of a "workaround", though it still uses window.top.location but not from a callback so maybe it will work (I'm just not sure where the callback is executed, since it's the fb sdk that executes it, maybe they call it from the fb iframe inside your iframe).
Instead of using client side authentication, you can use the server side flow.
The entire process is happening on the top window, since it starts by you redirecting the user to the oauth dialog using window.top.location.
When the process ends facebook redirects the user to your redirect_uri, and there you can simply redirect the user where ever you want.
I hope this will help.
Also, you should be aware that in the Facebook Platform Policies it states:
13 . The primary purpose of your Canvas or Page Tab app on Facebook must not be to simply redirect users out of the Facebook experience
and onto an external site.
It turns out the problem was occurring slightly earlier in the login process and the callback never got called. I did set a breakpoint in the callback (which wasn't called) but I thought the breakpoint might not work for some reason (perhaps because it was being executed in the context of another window).
Anyway, the problem was that the channel file (which the docs seem to suggest are optional) wasn't working properly, and this caused a problem with Safari but not with other browsers.

The page cannot be displayed error Facebook

This is the FB Url I am trying to access.
https://graph.facebook.com/oauth/authorize?client_id=694aa71aed60fb9d79aae04b81ff27c8&redirect_uri=http://localhost/TestConnect/Facebook.aspx&scope=email,user_about_me,user_interests,user_likes,user_location,user_notes,user_education_hi
It says
The page cannot be displayed
There are too many people accessing the Web site at this time.
It was working fine until last night
Even when I type it in the browser, it has no response. All it shows me is a green progress bar even after 20min
What should I do?
Thanks
SC
Here is your URL :
https://graph.facebook.com/oauth/authorize
?client_id=694aa71aed60fb9d79aae04b81ff27c8
&redirect_uri=http://localhost/TestConnect/Facebook.aspx
&scope=email,user_about_me,user_interests,user_likes,user_location,user_notes,user_education_hi
When changing redirect_uri to http://localhost it works fine for me. So I guess it is your page http://localhost/TestConnect/Facebook.aspx that does not works fine.
The redirect_uri will be called with GET parameters, be sure to handle them correctly :
If the user allows your app, he will be redirected to :
http://localhost/TestConnect/Facebook.aspx?code=...
and you will need to get a ask an access token to facebook with that code (the code parameter) by calling :
https://graph.facebook.com/oauth/access_token
?client_id=YOUR_APP_ID
&redirect_uri=YOUR_URL
&client_secret=YOUR_APP_SECRET
&code=THE_CODE_FROM_ABOVE
If the user doesn't allow your app, he will be redirected to :
http://localhost/TestConnect/Facebook.aspx
?error_reason=user_denied
&error=access_denied
&error_description=The+user+denied+your+request.
so you can detect that error by testing the get parameter error.
Hope that helps !