Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem getting access_token after migrating to OAuth 2.0

I have tried migrating my app to the OAuth 2.0 routine. I am having trouble getting the access_token from the cookie set by the JavaScript API. I decode the information in the cookie, but instead of an access_token and the user information I get a code. This seems like a rather weird change. Is there any workaround for this, because it seems that you can't get your code exchanged to an access_token when you haven't specified a redirect_uri when you acquired the code.

I have considered just taking the access_token from the response in the JavaScript API and storing it in a cookie, but that kinda defeats the whole purpose of the extended security and I wanted to ask if there was a proper way to do it.

Could be that I am doing something wrong though, and if that is the case please tell me :)

EDIT I am aware that the cookie holds a signed request, but according to the docs that signed request should hold the information I require like access_token and uid, but in my instance it only holds the code. That is basically the part I don't understand.

like image 497
Kasper Vesth Avatar asked Aug 26 '11 07:08

Kasper Vesth


1 Answers

Turns out that (even though it is not documented) we need to exchange the code for an access_token ourselves. I think this is a total waste since that was the nice thing about the old cookie. It was fast and easy to get the access_token.

Anyway. To get the access_token from the new cookie you need to do the following:

public string ReturnAccessToken()
{
    HttpCookie cookie = htc.Request.Cookies[string.Format("fbsr_{0}", facebookAppID)];
    string jsoncode = System.Text.ASCIIEncoding.ASCII.GetString(FromBase64ForUrlString(cookie.Value.Split(new char[] { '.' })[1]));

    JsonData data = JsonMapper.ToObject(jsoncode);

    getAccessToken(data["code"].ToJson()
}

private string getAccessToken(string code)
{
    //Notice the empty redirect_uri! And the replace on the code we get from the cookie.
    string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}", "YOUR_APP_ID", "", "YOUR_APP_SECRET", code.Replace("\"", ""));

    System.Net.HttpWebRequest request = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;
    System.Net.HttpWebResponse response = null;

    using (response = request.GetResponse() as System.Net.HttpWebResponse)
    {
        System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream());

        string retVal = reader.ReadToEnd();
        return retVal;
    }
}

public byte[] FromBase64ForUrlString(string base64ForUrlInput)
{
    int padChars = (base64ForUrlInput.Length % 4) == 0 ? 0 : (4 - (base64ForUrlInput.Length % 4));
    StringBuilder result = new StringBuilder(base64ForUrlInput, base64ForUrlInput.Length + padChars);
    result.Append(String.Empty.PadRight(padChars, '='));
    result.Replace('-', '+');
    result.Replace('_', '/');
    return Convert.FromBase64String(result.ToString());
}

This may seem a bit redundant, but I suppose you can store the access_token in a session variable. If you do this and iFrame the your app on Facebook you need to know that it will not work in IE 6, 7 and 8 if the user have set his browser privacy settings to medium. There is a workaround for this, but as it is not a part of this question I will not write it. If people really want it, write a comment and I will show it :)

-----------------------------------EDIT------------------------------------------

When using any of the old IE browsers you can't use cookies or session variables in pages that are Iframed in, like your pages on Facebook. This is a problem that can't really be solved sufficiently in coding. By sufficiently I mean that the solution is not nice. You need to set the p3p-header in your response. You can of course do this in coding for all the pages that you service, but the easiest solution (if you are using a .NET server to host your pages) is to set up a p3p policy for the IIS. A guide for this can be seen in http://support.microsoft.com/kb/324013. It shouldn't matter what you write in the p3p policy (if you check Facebooks own you can see that they use "We don't have a p3p policy), the important part is that there stands something. I have had troubles just using random text though, but if you use the text in the example there shouldn't be a problem :)

This took me forever to find out, so I hope someone can use it :D

like image 141
Kasper Vesth Avatar answered Sep 19 '22 01:09

Kasper Vesth