Facebook API’s ‘Invalid OAuth 2.0 Access Token’ error – a solution?
posted by robert | filed under social media, tutorials/samples
If you’re a developer of Facebook Apps you’ll be aware of the above-mentioned bug. If not, here’s a link to the bug details:
http://bugs.developers.facebook.net/show_bug.cgi?id=15933
The first thing you probably heard about it was when one or more of the Apps you’ve recently written (or are in the processing of developing) suddenly stopped working.
The bug was first reported on 17th March 2011 – pretty much the same time I realised that an App I’d written for a client and was about to release would no longer initialise properly and hence would need to be fixed. The symptoms of the problem are that, instead of the Facebook API returning a valid OAuth 2.0 Access Token, an invalid token is returned. Standard practice here is to redirect the user to a login/permissions prompt and thus start the authorisation process again.
The bug caused this process to fail consistently and many Apps simply looped indefinitely, unable to authorise correctly.
The App I’d worked on with a colleague, Neil Young, used the PHP Graph API libraries to establish a session and check for it’s validity, redirecting the user to the App’s login/auth URL if the session access token returned was not valid (or present). Once a session has been established, various Graph API calls were made to retrieve user information from Facebook before passing data into a Flash App (my part of the job).
It stopped working and looped indefinitely.
Today, Facebook (in the form of one of their staff, Douglas) responded to the priority 1 bug by saying:
We believe that the underlying issue here (cache inconsistency) has been resolved.
All of the access_tokens that we looked at fell into two categories: a cache issue or the user had logged out/changed password.
Naturally, the bug persists and a number of developers, myself included, have commented on this. Facebook have closed the bug as “resolved fixed”. Hardly.
Tired of waiting for a response, wishing to complete the App for the client and convinced that the issue is related not to changed user passwords (mine wasn’t changed) or “cache issues” (where, I ask?) but rather to Facebook having implemented undocumented changes to their PHP API to force us down the JS authorisation route, Neil and I decided to change the approach taken for the App in question:
- remove all use of the PHP API for authorisation and replace with JavaScript
- remove all PHP Graph API queries from the index.php page itself and implement them in the AMFPHP gateway used by the Flash App to retrieve database data anyway
I spent some time this afternoon removing all of Neil’s PHP-based authorisation and login/permissions redirect and replaced it with an ExternalInterface call from within the Flash App to trigger a JavaScript call to FB.login with the required permissions and the following code (abbreviated):
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
//get the user from the facebook api
FB.api('/me', function(response) {
//api call worked so tell the flash!
sessionConnected();
});
}
else{
//user is logged in, but did not grant any permissions
//build content
$("#dialogue").dialog( "option", "title", 'Permissions Error' );
$("#dialogue").dialog({ buttons: { "Close": function() { $(this).dialog("close"); } } });
var data = {"contents":{"success":0,"feedback":{"messagesType":"error","message":"You did not accept the required permissions"}}};
$("#dialogue").html(BuildFeedbackMessage( data.contents ));
$("#dialogue").dialog( "open" );
}
} else {
// user is not logged in
//build content
$("#dialogue").dialog( "option", "title", 'Permissions Error' );
$("#dialogue").dialog({ buttons: { "Close": function() { $(this).dialog("close"); } } });
var data = {"contents":{"success":0,"feedback":{"messagesType":"error","message":"You did not accept the required permissions"}}};
$("#dialogue").html(BuildFeedbackMessage( data.contents ));
$("#dialogue").dialog( "open" );
}
}, {perms:'publish_stream'});
The sessionConnected(); method simply calls a method in the Flash App via ExternalInterface to tell the App it can continue loading, at which point it calls methods via the gateway to retrieve data.
If the user is either not logged on or hasn’t granted the required permissions, a dialog is displayed asking them to do so.
This works. Even the FB.api(‘/me’, function(response) block executes without any issues. The flash receives the confirmation call back from JavaScript and continues on it’s merry way, doing what it should.
Now. My password hasn’t changed and I can’t see how any form of cache issue could lead to this solution working where the other didn’t.
I also didn’t uninstall the App or make any changes to my App permissions settings – simply made the changes mentioned above.
Maybe this’ll work for you too. It’s a solution and not a workaround. I don’t like workarounds as my clients won’t pay for me to go back in a month’s time and rework something. They expect a finished product to be a finished product – and I can’t blame them.
The problem with Facebook’s approach to their platform and to App developers is that we all have to work to a moving target, an inherently unstable platform. Such a platform is not really suitable for producing the kind of campaign-based Apps that I produce but Facebook market their platform as THE socially-aware marketing platform for campaign-based Apps.
It’s about time they started to run it like one – got some decent QA in place and thoroughly tested their releases before throwing bug-ridden code out into the World.
If you’d like to voice your thoughts on this, either do so in the comments or, better, go along to the Facebook Page we’ve set up and add your voice there:
Developers’ Rights: http://www.facebook.com/pages/Developers-Rights/206834912671201?sk=wall
Good luck in getting your Apps running!
ps. It’s worth noting that the user experience is now identical to that previously found in external website using Facebook Connect and not the seamless experience which we used to be able to offer with the REST API or even the latest PHP Graph API approach taken prior to this bug appearing. This is why I’ve labelled this post “a solution” – it’s not ideal.
5 responses to “Facebook API’s ‘Invalid OAuth 2.0 Access Token’ error – a solution?”
-
Thank you so much Robert! I hope Facebook gets it together!
-
if the issue was an access_token, this workaround wouldn’t work at all, as the same authn/z codepath is used.
as i said in the bug, my guess is that you were using a older version of the PHP SDK that depended on something we changed around the same timeframe (the current version of the SDK works fine).
-
Thanks Douglas – my point exactly. The solution highlights the fact that the issue can’t be as simple as the access token issue. We were also using an up-to-date PHP SDK, as were others who are still experiencing the bug. Something is seriously broken in the platform and it’s great that you’re pushing for a proper solution!
Your answer also includes one important – no, dramatically critical – point: You (Facebook) are constantly releasing unannounced updates which break existing functionality and DO NOT support backward-compatibility!
This is totally unacceptable for a platform upon which people base commercial applications. As I’ve written before, I cannot expect my clients to pay me again for work made necessary by Facebook’s failure to provide backward compatibility in SDK changes. Once a project is completed a client pays for the work done and expects it to continue working. It’s unacceptable for the platform to break at the whim of Facebook and this sort of thing needs to stop happening. The platform needs to mature and become much more robust given the number of developers who depend upon it.
Thanks for putting up with my ranting. I hope we can learn from this situation and make some progress towards avoiding issues like this.
(copy of my response on the bug log)
-
[...] accepting the required permissions. This code can be found on my colleague Robert Turall‘s blog post but I will add a version for you to look at on my blog [...]
-
[...] accepting the required permissions. This code can be found on my colleague Robert Turall‘s blog post but I will add a version for you to look at on my blog [...]


