Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Facebook Graph API with the JS SDK in a canvas page iFrame in Safari is broken

So I'm trying to use the Graph API with the Facebook JS SDK and I'm getting the following error in Safari:

"OAuthException: An active access token must be used to query information about the current user."

I suspected it had to do with the fact that Safari is very strict with x-domain cookie setting and so I tried it in Firefox with cookie option set to false in FB.init(). I indeed found that I was getting the same error for my FB.api() requests.

FB.init({
  appId:  "<%= app_id %>",
  status: true, // check login status
  // We cannot rely on this cookie being set in an iframe. I found this
  // out because the Graph API was not working in Safari.
  // cookie: true, // enable cookies to allow the server to access the session
  xfbml:  true, // parse XFBML
  channelUrl: window.location.protocol + '//' + window.location.host + '/fb/canvas/channel.html'
});

So I'm wondering... is there a good way to manually set the access_token query parameter in the FB.api() request?

If the FB.init() cookie gets properly set, this is what the FB.api() request parameters look like:

access_token  xxxxxxxxxxxx|1.xxxxxxxxxxxxxxxxxxxxxx__.3600.xxxxxxxxxx-xxx|xxxxxxxxxxxxxxxxxxxxxxxxxxx
callback      FB.ApiServer._callbacks.xxxxxxxxxxxxxxx
pretty        0
sdk           joey

In Safari (or when the cookie FB.init() option is not set) the FB.api() request parameters look like:

callback      FB.ApiServer._callbacks.xxxxxxxxxxxxxxx
pretty        0
sdk           joey

Now... obviously my app has the ability to generate the access_token on the server side... I'm wondering if there's any way I can manually set FB.api() to use my server-side-generated access_token.

like image 623
Aaron Gibralter Avatar asked Feb 01 '11 07:02

Aaron Gibralter


2 Answers

Ok I got it to work. I turns out you don't need the FB.init() cookie: true option in order to use FB.api()--you can manually pass the access_token:

FB.api("/me/apprequests/?access_token="+access_token, function (response) {});

Where access_token is a JS variable that you set server-side on page load. Here is an ERB example:

<script>
  var access_token = "<%= @access_token %>";
</script>

And @access_token is the oauth access_token that gets passed to your canvas page in the initial POST request.

like image 182
Aaron Gibralter Avatar answered Nov 01 '22 22:11

Aaron Gibralter


The limitation with Safari is that it will not allow the contents of an iframe to create or use cookies if the domain is different to the parent... unless the user interacts with it first. The problem is unique to Safari not webkit, so Chrome is fine.

After running into this problem myself (several painful times), there is a solution which appears to be a good work around. The technique is to inject a form into the page body using javascript and then trigger the submit event. Safari accepts this as a user interaction and allows cookies.

You can find a good example on the Facebook developer forum here

like image 25
leebriggs Avatar answered Nov 01 '22 22:11

leebriggs