I've been battling with this all morning.
I'm actually trying to get custom Open Graph Actions to work. I've succeeded in this, piecing together bits of information from here and there and everywhere, and now I have a button which posts a "Want" action with the following flow:
> User Clicks Button
> FB.api checks response.
> if response code is 200 the user has not granted publish_stream permission
> call FB.ui({ method:
"permissions.request",
"perms": 'email,publish_stream'
}
> call back to original function and post to stream
> if user has already granted permission, then just publish
That all works lovely.
What I need though, is to catch a case where the user is not logged in to Facebook at all.
This appears to be response code 2500 where no access token is present
SO I have this code snippe, which catches that case
.....
} else if (((response.error.code) * 1) == 2500) {
doLogin('publish_stream', postWant, itemId);
// post want being the original function and itemId being the item we are "wanting"
}
my doLogin function looks like this:
function doLogin(permRequired, callingFunction, urlAppend) {
FB.ui({
method: 'oauth',
scope: 'email,' + permRequired
},
function (response) {
// DO THINGS NOW WE'RE LOGGED IN
});
};
This is basically exactly the same as my function to get the extended permission, which looks like this:
function getPermission(permRequired, callingFunction, urlAppend) {
FB.ui({ method:
"permissions.request",
"perms": 'email,' + permRequired
},
function (response) {
// DO THINGS NOW WE HAVE PERMISSION
});
};
This latter example WORKS, but the Login example just loads a popup saying "Sorry, something went wrong, please try again later"
Obviously FB.init is already called, the APP is set up correctly, APP_ID declared in FB.init and so on, clearly, as the other stuff works.
FB Login froma FB Login button works, but I need this to work through this flow in order for the "frictionless" behaviour to operate (ie, I can't have another button to click)
Don’t use FB.ui with method:"permissions.request" – just use FB.login, and set the options parameter with the scope of (additional) permissions you require.
https://developers.facebook.com/docs/reference/javascript/FB.login/
Related
We have an FB.login call like this:
FB.login(function (response) {
if (response.status === 'connected') {
responseFunction(response.authResponse.userID);
} else {
responseFunction(null);
}
}, { scope: requiredPermissions.concat(optionalPermissions).join(','), return_scopes: true });
It properly detects a canceled login if the user didn't connect to the app yet. However, if the user is already connected when they cancel the login, response looks like this:
authResponse: {
accessToken: "token",
data_access_expiration_time: 1560437437,
expiresIn: 86963,
reauthorize_required_in: 7776000,
signedRequest: "bababa",
userID: "userid"
},
status: "connected"
Almost exactly like a successful login response. Luckily, there is also a grantedScopes field in the response if the login has been finished properly (because of a return_scopes option). However, using it to distinguish between the 2 seems unreliable and hacky.
Is there a better way?
Thank you in advance!
Update:
Why not use FB.getLoginStatus instead?
For the context: in my case, FB.login is used to be granted access to the user's pages. It is not used to log them into the app, per se.
I'll be happy if someone points at a mistake in my reasoning. Here it is:
Calling FB.login right after FB.getLoginStatus is unreliable due to the modal block in browsers. FB.login needs to be called synchronously within a click handler.
FB.getLoginStatus result may and will expire if called before showing the button calling FB.login. A user may and will spend a lot of time on this particular page before clicking the button.
That's why the button click handler immediately calls FB.login. It helps avoid both of the mentioned issues.
I ended up using the presence of grantedScopes in response as an indicator of a complete login.
I created an Android App with PhoneGap:Build and the FB Connect Plugin. The app works fine and the FB Plugin, too. Just one tiny thing isn't working yet. I won't to post something after submiting a button which works, too. At the first time the user has to login and grant permissions to the FB App and them the post is published. That's the way it should be. And the next time the user submits the post should be published without the whole permission thing but this isn't working!? FB shows a message like "You already granted permission ... to the app." and the user has to push the Ok-button before the post is published???
Because I still haven't found an answer for my question, maybe I just do something wrong in my FB Javascript call? Here is the current code:
FB.login(function(response) {
if (response.authResponse) {
var data = {
...
}
FB.api('/me/feed', 'post', data, function(response) {
// Callback
if (!response || response.error) {
// ERROR
}
});
} else {
// ERROR
}
}, {scope: 'publish_stream'});
Well, to better understanding here a picture of the screen that apears every post:
http://i.stack.imgur.com/bZrde.png
Thx,
Daniel
I think the solution to this problem is to not include the login request every time you want to post something. You can check login status, and/or permissions, without performing a login. Then, if the user is not logged in, do the login first, and come back to the new post action.
In my Facebook application, I am requesting 3 scopes: email,publish_stream,publish_action
I am using the FB.login function. These 2 steps pop up.
When the user clicks "Cancel" in the first step, FB.login will show "status: unknown" as the response object.
However, when user clicks cancel in the second step, FB.login shows it as "status:connected" and treats it as if the user accepted everything.
I recently learned that you can check if the user allowed the 2nd step using
FB.api('/me/permissions', function (response) {
console.log(response);
} );
My question is...knowing that the user denied the open graph step, how can I pop that dialog up again?
You are correct, the 2nd stage of the Auth Dialog is optional, the user does not have to accept all of the extended permissions you ask for, or any of them, as it states in the Permissions sections of the auth dialog documentation:
The user will be able to remove any of these permissions, or skip this
stage entirely, which results in rejecting every extended permission
you've requested. Your app should be able to handle revocation of any
subset of extended permissions for installed users.
The best approach I think is to have your app manage with what the user accepts, but if you HAVE to have the permission(s) in the optional stage (extended permissions) then this is what you can do:
FB.init({
....
});
var requiredPermissions = ["email", "publish_stream", "publish_action"];
function checkPermissions(response) {
var ok = true;
if (!response.data || response.data.length != 1)
ok = false;
else for (var perm in requiredPermissions) {
if (!(perm in response.data[0])) {
ok = false;
break;
}
}
if (!ok)
login();
else
console.log("Hey there user who granted all the required permissions");
}
function loginCallback(response) {
if (response.authResponse) {
FB.api("/me/permissions", checkPermissions);
}
else {
console.log("User cancelled login or did not fully authorize.");
}
}
functoin login() {
FB.login(loginCallback, { scope: requiredPermissions.join(",") });
}
I haven't tested this code, it's a nudge in the right direction though.
Also, this code will go on forever until the user accepts all permissions or just gives up, you should somehow let him know that you need those permissions and about to send him for the auth dialog again.
Edit
I keep forgetting to include this with my answers:
Calling FB.login opens a new pop-up window, and browsers usually blocks that unless it's a result of a user action, as it says in the docs:
Calling FB.login results in the JS SDK attempting to open a popup
window. As such, this method should only be called after a user click
event, otherwise the popup window will be blocked by most browsers.
It also says there:
If you need to collect more permissions from users who have already
authenticated with your application, call FB.login again with the
permissions you want the user to grant. In the authentication dialog,
the user will only ever be asked for permissions they have not already
granted.
Which means that it's a way to do what you want, the popup probably did not open because it was blocked by your browser.
You need to modify the code I gave you so that every time you call the login function it's after the user interacted with your page, i.e.: display a message saying "the application needs this and that permissions, please click this button to continue" which then will call the login function.
I used the old rest api for showing the Permission Dialog in Facebook before.
Now, with the new graph API, what can I do? (I'm in IFrame Apps).
I know that I can cheat and popup the permission in a seperate window:
FB.login(function(response) {
if (response.session) {
if (response.perms) {
// user is logged in and granted some permissions.
// perms is a comma separated list of granted permissions
} else {
// user is logged in, but did not grant any permissions
}
} else {
// user is not logged in
}
}, {perms:'offline_access'});
like that.. call the FB.login again (let say I want people to click on a different button and trigger the extended permisison dialog)
However,it looks ugly,and it doesn't look like a dialog.
Is there a way to generate the dialog? I try to figure out whether FB.ui can help but there is only little information about that.
In addition, I don't think the 'response' callback ever execute. Neither I click "Don't allow" or "allow", won't trigger any call back. any idea?
hihih..anyone can help me?
Finally. find out the solution from another website.
first. after FB.init( ... ); do that:
FB.provide("UIServer.Methods",
{ 'permissions.request' : { size : {width: 575, height: 300},
url: 'connect/uiserver.php',
transform : FB.UIServer.genericTransform }
} );
Then, whenever you need to call the permssion dialog, do that:
FB.ui({method: "permissions.request", "perms": 'email,offline_access'},
callBack);
It took me so long to figure out by looking at the FB object and find out there is UIServer with permissions.request then from that, I keep searching and find this solution. and FB.ui talks nothing about it.. and FB.provide is not documented. THANKS facebook.
You don't need to use javascript or any SDK for this although it would make it easier. You need only to redirect the user to a url like this:
https://graph.facebook.com/oauth/authorize?
client_id=...&
redirect_uri=http://www.example.com/callback&
scope=user_photos,user_videos,publish_stream
You should always redirect the user to the top window either with javascript or the link.
window.top.location = <login_url> or Login
If you are using the PHP SDK or the C# SDK you could have the sdk generate the url for you, but the process is the same.
Also, not that the redirect_uri has to be on the same domain as your iFrame application's url. This will cause Facebook to redirect your user outside of Facebook to your website, you then should redirect the user back to the app inside of facebook. For example:
User clicks login
user goes to Facebook login page
User clicks allow
Facebook redirects the user to http://www.example.com/callback
Your app redirects the user to http://apps.facebook.com/myapp/loggedin
One of the answers suggests a hack in which you call FB.provide() and then FB.ui() to pop up the extended permissions dialog. That solution doesn't work for me, but there is a documented solution now that does. Just call FB.login() to get the permissions you need.
FB.login(function(response){
if (response.authResponse) {
alert('success!');
} else {
alert('fail!');
}
},{scope: 'email'});
Even better, you can ask for extended permissions with the login button.
it is incredibly easy to hide content from someone who does not like your application...if you're using FBML. I'm using an iFrame and the JavaScript SDK, and am having terrible difficulty figuring this out.
The behavior I'm seeing (both logged in and out) is that does not seem to be supported by FB.XFBML.parse(). Am I mistaken or is there an alternative method I can use that does not require the user to give explicit permission?
Finally figured it out!
After you have initialized the api (using FB.init()) simply do the following:
FB.api('/mypage', function (response) {
FB.api({ method: 'pages.isFan', page_id: response.id },
function (response) {
alert(response);
});
});
When the '/mypage' response comes back, it has the page id of the profile. Use that in the pages.isFan call and it will return a boolean object telling you if the current user has Liked that page or not.
No need to deal with authentication, extended permissions, or any FQL.