This question has been asked a few times on Stack, but there have been no real answers. Let me try to explain my situation anyways.
We use an application that uses Facebook OAuth2 login. This login used to work fine till last week, and all of a sudden it is troubling us now.
Application Flow:
Step 1: User presses login with Facebook button on our website
Step 2: Redirected to Facebook login/authorization page
Step 3: On authorizing the app, the callback comes to our application, with a short lived "code" param.
Step 4: This "code" param would be exchanged for a 60 day Access token using "https://graph.facebook.com/oauth/access_token" URL.
Error in Step 4:
When we try to exchange the short living "code" for the access token, we get this error from Facebook.
{"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100}}
Observation:
What I already got from Forums:
Here is my interpretation of what I read. May be inaccurate. Facebook has some weird policy that necessitates the app developer to maintain the temporary 10 minute code until the 60 day code that was obtained during the first login expires. So we should create a cookie with the Access token on the user's browser. I was even able to see people modifying their code in order to create the cookies.
What's really bothering me?
Edit:
Platform: Python, Google Appengine. We do not use any Facebook SDKs, we make direct HTTP Calls to all the login URLs. Call that fails : https://graph.facebook.com/oauth/access_token - we are passing the appId, secret and code (obtained from facebook) within 20 seconds of the first call happening.
Hope there is enough information here to show that our code is not totally incorrect. Any tips/pointers from people who have encountered and solved this problem is Welcome. If its a Facebook bug, and the Facebook dev comes to notice, I would be even happier.
I got round this issue by using a random GUID which is appended to each callback url i pass into facebook. It seems the code that facebook returns is made up of a few parts including the redirect_uri parameter you have to specify. By using this GUID trick, your app continues to work but facebook thinks it's a different URL hence generating a new code.
If you store that GUID in a temporary session, it's always the same. Here's a very cut down version of what I mean. I'm using C# but the solution will be the same:
Before i start the oauth process:
Session["facebook_buster"] = System.Guid.NewGuid().ToString();
Then to kick off the login:
var facebook = new FacebookClient();
var loginUrl = facebook.GetLoginUrl(new
{
client_id = ...,
redirect_uri = ..."/facebook/oauthcallback?buster=" + Session["facebook_buster"].ToString(),
display = "popup",
scope = "publish_stream,user_photos"
});
And then in my callback method, when I want to exchange that code for a new access_token:
var facebook = new FacebookClient();
dynamic result = facebook.Post("oauth/access_token", new
{
client_id = ...,
client_secret = ...,
redirect_uri = ..."/facebook/oauthcallback?buster=" + Session["facebook_buster"].ToString(),
code = Request["code"] // this is the returned code from the first method
});
Note in that second method i'm using the same session key so that the authorization code is successful.
Been testing this all morning by revoking permissions / manually changing my stored access_token (in my db) / removing my stored access_token completely and it works every time.
Hope this helps!