Access token error when trying to post a Facebook score in a canvas application - facebook

I'm trying to integrate the scoring system in my canvas app with Facebook's, implemented using MVC 3 and the 5.2.1.0 Facebook SDK.
A simplified hello-world variant of my game controller looks like:
public class MyController : Controller
{
[CanvasAuthorize("publish_action" /*And some others*/)]
public ActionResult Index()
{
var fb = new FacebookWebClient();
var scores = fb.Get("/me/scores"); // Works (I think)
fb.Post("/me/scores", new { score = 10 }); // Throws an exception
}
}
The call to get scores looks like it's giving me something sensible; the call to write a score value throws "(OAuthException) (#15) This method must be called with an app access_token."
What've I missed? The application id and secret are correctly set in my web.config - for example, I can successfully post an application apprequest in other parts of the actual application not shown in this stripped down test copy. Rummaging around with the debugger shows me that the FacebookWebClient object contains a non-empty access token field, and that that's included in the URI that fb.Post eventually uses.
The Facebook scores page (that Björn links to) mentions only publish_actions but I've tried including other pertinent sounding permissions, such as offline_access and user_games_activity to no effect.
I am assuming that the CanvasAuthorize attribute does the login correctly - it certainly seems to let me send an application apprequest, so it looks as if it's doing the right thing...

Your app needs the permission to write to the users profile. You can use the Graph API to request the required permissions from the user. If granted, Facebook will give you the required access token that you can then use in your request to Facebook. This practice ensures that you only perform actions, the user allowed you to.
Edit_: After looking at the docs: Are you sure you have the required permissions from the user like described here http://developers.facebook.com/docs/score/ ?

Please see this link. You'll need to get an facebook app. Using the apiId and SecretId, you can then post using the information in the link below. The key is adding &scope=manage_pages,offline_access,publish_stream to the url.
like so:
"https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials&scope=manage_pages,offline_access,publish_stream";

Related

Facebook login - what on earth am I doing wrong

I'm tearing my hair out here.
We've got a web app that is hosted on a bunch of different domains and we have a facebook login on the page. This works just peachy. Most of them run of our root domain eg newsite.ourplatform.com and we reuse the same facebook app and add a new domain in.
We've had a request to set up a new site on a different url. In the past, this hasn't really been a problem. We set up a new facebook app, add the appid to out config and voila, facebook login working. (we don't do this so often, so I've potentially broken it)
This time around. I've set up a new app id and plugged it in, but whenever I call the facebook login, it authenticates me, but I get a useless response from facebook.
eg. On a working site I call
FB.api("/me/", function(response){console.log(JSON.stringify(response));});
and get response
"{id":"12345678910","email":"my#email.com","first_name":"My Name","gender":"male","last_name":"Myname","link":"https://www.facebook.com/app_scoped_user_id/12345678910/","locale":"en_GB","name":"My Name","timezone":10,"updated_time":"2014-01-19T10:44:20+0000","verified":true}
but on the broken site I do the same call and get a response
{"name":"MyName","id":"12345678910"}
Which is sort of good, but I need their email. As far as I can tell, I'm not asking for any permissions beyond email,public_profile and user_friends
Because of the way the app setup works, we have different apps running 2.1, 2.2 and 2.4 and this new one on 2.4 doesn't work. I'm not sure if that's a red herring or if I've got a misconfigured facebook app.
(edit - removed the sites affected to protect the innocent)
As #CBroe said you really need to checkout the v2.4 changelog for the API. In version 2.4 of the API Facebook introduced 'declarative fields'. This means that when you make a base request, like to /me you will only get a small amount of info back, e.g. 'name' and 'id'.
You have two options to get more fields:
Option One
FB.api('/me?fields=first_name,last_name,gender', function(response) {
console.log(response)
});
Option Two
FB.api('/me', function(response) {
console.log(response)
}, {'fields': 'first_name, last_name, gender'})
This will return a response that looks like the following:
{"first_name":"First", "last_name":"Last", "gender":"gender", "id":"ID"}
The key in the request above is specifying the fields URL parameter in your request and is documented in the link #CBroe linked and I have linked above.

MVC5 Facebook get users photos

I am building a website app in MVC5 that allows a user to login using Facebook/Twitter. Once they are logged in we will look through their photos for ones marked with a certain hashtag.
I have the login working for both FB and Twitter - and using Linq2Twitter I can get the and post photos.
However with Facebook I am having some problems. My understanding with Facebook is that after the login I have to make a second call to https://graph.facebook.com/oauth/access_token in order to get a short lived access token.
However this call requires a "code" and a returnUri. I am unsure what this code is or how to get it, and what return URI to use.
My startup.Auth.cs looks like this
var facebookOptions = new FacebookAuthenticationOptions();
facebookOptions.Scope.Add("user_photos");
facebookOptions.AppId = ConfigurationManager.AppSettings["facebookAppId"];
facebookOptions.AppSecret = ConfigurationManager.AppSettings["facebookAppSecret"];
app.UseFacebookAuthentication(facebookOptions);
And everything logs in fine and I end back at ExternalLoginCallback
So where do I go from here. How do I find this code and what returnUri do I use in order to get the access code.
Once I have this access code I plan to call (https://developers.facebook.com/docs/graph-api/reference/v2.1/user/photos)
Hopefully I am going about this the correct way and my question makes sense
Many thanks.
Okay - This solves my problem
http://blogs.msdn.com/b/webdev/archive/2013/10/16/get-more-information-from-social-providers-used-in-the-vs-2013-project-templates.aspx

In terms of privacy, is it acceptable to extract the user id from a Facebook share response to make use of that user's details?

Using the Facebook API, you can get back the post ID of a Facebook share, even if the user has not authorized your app.
The post ID is prefixed by your user ID, and separated by an underscore.
FB.ui({
method: 'feed',
name: 'People Argue Just to Win',
link: 'http://www.nytimes.com/2011/...',
}, function( response ){
// Response gives you :
// { post_id: "[fbUserId]_346759642059572" }
});
To me it looks like Facebook is using this programmatically, rather than with the idea of providing us the userId out of the kindness of their hearts. But it's extremely tempting to use.
I'm a little rusty on permissions - if there is a way to get back all the users that have liked/shared a specific URL, and not just a count, then this should be okay.
But the question remains, is it acceptable to use?
EDIT:
Now that I think about it, you can access the user ID by making an anonymous call to https://graph.facebook.com/[postId] but ONLY if the post was made public.
If you get a response from FB, it means that you have already ask the user for the required permissions,
so yes you can use the data returned from Facebook as you like, but you always have to inform the users how you use those data.
You can only cache user data if you have permission or it is necessary for the function of your app. Using the like button you can subscribe to edge.create and cache the response from the like.
refer to: http://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/
II. Storing and Using Data You Receive From Us
You will only request the data you need to operate your application.
You may cache data you receive through use of the Facebook API in
order to improve your application’s user experience, but you should
try to keep the data up to date. This permission does not give you any
rights to such data.
in my app i store the id of every page or user that is viewed to speed up page load times and count page views. Seems with in the scope of Policy as long as i am not sharing the info with 3rd parties or making public what a user has set to non public.

Access Facebook albums from a flash app

I want to create a flash Facebook application in which, after pressing a button, the user will be able to browse his/her photo albums and choose a photo. How should i do that? What will be the code under the button to gain authentication from any user using this application?
Thanks.
I am currently writing a facebook application for a university assignment that will allow the user to do everything you can do in facebook, but via the flash player window. You will need a few basic things happening in order to do it.
User log in and authentication - this must be done via Facebook - using OAuth authentication, and meeting all of facebook's security policies
register the application with facebook
Use the Graph API (facebook's developer's toolkit) to get the necessary functions that will communicate with facebook via flash.
In Flash itself you will use a bunch of URLRequest functions to send out to FB for information, then you will need to retrieve that data responses and store them to variables (extracting data with a few lines of code is easy, something like this;
//initialise variables
public var photoURL:String;
var Request:URLRequest = new URLRequest("http://www.whatever the url for the graph api service you are using which is founf from FB");
//that ^^ will send off a request for the url, you then want to use the returned data by registering an event handler like this below
functionName.addEventListener(onComplete, completeHandler);
functionName(event, EVENT)
{
var loader:URLLoader = new URLLoader(Request);
var data:XML = new XMLData(load.loader); //i think this is right but not 100% sure, fiddle with it
//then you want to extract the data that is returned, for example, extracting xml data from a rest request works by hitting data from the xml by specifying a path to the object you want. an example of xml is this <rsp stat="ok"><photos ......more code="morecode"><photo url="url of photo"></photo</photos> so you can hit the url in that example like this;
photoURL = data.photos.photo.#url; //this line will grab the photo url for you, allowing you to dynamically create an array and assign photos to the flash stage according to the url you get
}
this is fairly advanced stuff and I am assuming that you have some decent knowledge on AS3, XML, and the FB API, if you need more help just reply

Facebook API: FB.Connect.requireSession issues

I have a Facebook app that is built as an iFrame. I am using the JavaScript client API loaded via:
http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php
In my initialization code, I use the requireLogin method to ensure that the user has authorized the app. I have found this to be necessary to be able to gather the user's name, avatar, etc. for the scoreboard. Here's a representative code snippet:
FB_RequireFeatures(["Connect","Api"], function() {
FB.Facebook.init("...API_KEY_HERE...", "xd_receiver.htm");
var api = FB.Facebook.apiClient;
api.requireLogin(function() {
api.users_getInfo(
FB.Connect.get_loggedInUser(),
["name", "pic_square", "profile_url"],
function(users, ex) {
/* use the data here */
});
});
});
This causes the iframe to redirect causing the Facebook authorization screen to load within my app's iFrame. This looks junky and is somewhat confusing to the user, e.g. there are two Facebook bars, etc.
Question 1: is there anything I can do to clean this up while still implementing as an iFrame, and still using the JavaScript APIs?
According to the FB API documentation:
FB.ApiClient.requireLogin
This method is deprecated - use
FB.Connect.requireSession instead.
My experience though when I replace api.requireLogin with FB.Connect.requireSession it never gets invoked. I'd prefer the recommended way of doing it but I struggled and was not able to find a way to get it to work. I tried adding various arguments for the other two parameters as well with seemingly no effect. My expectation is that this method will load in a dialog box inside my app iFrame with a similar authorization message.
Question 2: what am I missing with getting FB.Connect.requireSession to properly prompt the user for authorization?
Finally, at the end of the game, the app prompts the user for the ability to publish their score to their stream via FB.Connect.streamPublish. Which leads me to...
Question 3: am I loading the correct features? Do I need both "Api" and "Connect"? Am I missing any others?
Here is a summary of the changes I needed to make to clean up the authorization process. It appears that iFrames must fully redirect to properly authorize. I tried using the FBConnect authorization but it was a strange experience of popup windows and FBConnect buttons.
Ultimately this game me the expected experience that I've seen with other FB apps:
FB_RequireFeatures(["Connect","Api"], function() {
var apiKey = "...",
canvasUrl = "http://apps.facebook.com/...";
function authRedirect() {
// need to break out of iFrame
window.top.location.href = "http://www.facebook.com/login.php?v=1.0&api_key="+encodeURIComponent(apiKey)+"&next="+encodeURIComponent(canvasUrl)+"&canvas=";
}
FB.Facebook.init(apiKey, "xd_receiver.htm");
FB.ensureInit(function() {
FB.Connect.ifUserConnected(
function() {
var uid = FB.Connect.get_loggedInUser();
if (!uid) {
authRedirect();
return;
}
FB.Facebook.apiClient.users_getInfo(
uid,
["name", "pic_square", "profile_url"],
function(users, ex) {
/* user the data here */
});
},
authRedirect);
});
For iFrames, the solution was ultimately to redirect to the login URL which becomes the authorization URL if they are not already logged in.
I think that FB.requireSession only works from a FB connect site outside of
Facebook. If you're using an app hosted on apps.facebook.com use the php api
call instead,
$facebook = new Facebook($appapikey, $appsecret);
$facebook->require_login();
or link to the login page.
Of these methods to login
* Using the PHP client library
* Directing users to login.php
* Including the requirelogin attribute in a link or form
* Using FBML
only the first 2 are available to iframe apps hosted on apps.facebook.com
I think requirelogin and fbml only work with fbml canvas apps.
see
http://wiki.developers.facebook.com/index.php/Authorization_and_Authentication_for_Canvas_Page_Applications_on_Facebook
Question 1: is there anything I can do
to clean this up while still
implementing as an iFrame, and still
using the JavaScript APIs?
Question 2: what am I missing with
getting FB.Connect.requireSession to
properly prompt the user for
authorization?
Please have a look at this. This article discusses correct use of require session and provides links on how to implement that. And yes, you are right, the requireLogin has been deprecated and won't help any more.
Question 3: am I loading the correct
features? Do I need both "Api" and
"Connect"? Am I missing any others?
As far as I know, you can use both API and Connect together, basically you access Facebook's API with the help of JavaScript.
For iframe apps however, there is no great help and minimum support of API with some handful functionality available. See this for more info.
This causes the iframe to redirect
causing the Facebook authorization
screen to load within my app's iFrame.
This looks junky and is somewhat
confusing to the user, e.g. there are
two Facebook bars, etc.
Finally and personally I have not seen any iframe app requiring user to add the app first. This will create the problem of two bars you mentioned as quoted above.
The link I posted at the beginning of my answer has some useful links to get you started and decide the next-steps or possibly making changes to your apps.