Den Delimarsky

I am an engineer working on API documentation, security and machine learning.

github twitter linkedin email rss

Facebook API from C# – Getting the list of friends

Apr 1, 2010
7 minutes read

Facebook has a very useful API, that can give the developer access to pretty much anything Facebook-related when it comes to user profiles. The documentation provided comes in handy and it shows how to use the API from a web developer’s perspective – mostly giving examples in PHP. What if the developer wants to work with managed code in a desktop application? Since I am working with C#, I tried to implement some of the API calls in this language. And surprisingly, it went pretty well. Here is what I did and how I was able to do it.

I was very curious about the possibility of getting the list of friends for my Facebook profile through a desktop application and I didn’t want to use the Facebook SDK since I am curious about the internals of the process rather than the plain class declaration and usage. First of all, Facebook’s REST API isn’t that complicated if the developer is familiar with HTTP requests. Its REST API is completely based on them. I am not talking about Facebook Connect.

All REST API requests go through http://api.facebook.com/restserver.php. That is the main gateway for the data that is sent by the client application, as well as for the data received. You can obtain the data in two formats – XML or JSON. Since at this point, .NET Framework doesn’t provide JSON parsing capabilities, I am going to focus on the XML representation of the data, it being the default formatting.

Facebook API calls require the developer to provide some unique authentication information. For a single application, that is the API key and the secret key. Both are obtained from Facebook once you start a new application project.

To start, I went to http://www.facebook.com/developers/apps.php and set up a new application. Once I was done, I got an API key and the secret key, as well as the application ID.

Image lost since old blog

Now I am all set to start with managed code. But before, I had to understand the way Facebook lets the user get the data. There are three key components in this process and you can see them in the image below:

Image lost since old blog

First of all, the developer needs to create an authentication token. It is generated fairly easy – all I needed to do is pass these required parameters to the REST API URL: api_key (represents the API key I got when I registered my application), method (represents the currently used API method – Auth.createToken in this case), v (its value should always be 1.0 – it represents the version of the API) and sig.

The sig parameter is the signature. And it has an interesting generation algorithm. Here is the structural scheme of a API call signature:

Image lost since old blog

First of all, all the required parameters for a specific API calls are sorted alphabetically (with the values assigned accordingly) and are concatenated in a string variable, without any delimiters. Then, the secret key (obtained at application registration) is appended to that string.

Once this is done, a MD5 hash should be generated for the concatenated string. And here is the signature.

IMPORTANT NOTE: A MD5 hash contains alphanumeric characters. It is important that all the letters are in lowercase (by default, a MD5 hash in C# is generated with uppercase letters. This is easily fixable if the ToLower() function is applied to the string.

Once all parameters and their values are ready, those are assembled in a request string, that is later on passed to the REST API URL.

The code representation for the process above is below:

public static string CreateToken(string apiKey, string secret)
{
    // Defines the REST API URL.
    string host = "http://api.facebook.com/restserver.php";
    // The returned result.
    string result = string.Empty;

    // The raw signature string.
    string _signature =
          "api_key="
          + apiKey
          + "method=Auth.createToken"
          + "v=1.0"
          + secret;

    // Create the MD5 hash of the raw signature string.
    MD5 md5 = MD5.Create();
    byte[] init = Encoding.ASCII.GetBytes(_signature);
    byte[] hash = md5.ComputeHash(init);
    StringBuilder signature = new StringBuilder();
    for (int i = 0; i < hash.Length; i++)
    {
       signature.Append(hash[i].ToString("X2"));
    }

    // Prepare the parameters that will be passed to the server.
    Dictionary<string, string> parameters = new Dictionary<string, string>();
    parameters.Add("api_key", apiKey);
    parameters.Add("method", "Auth.createToken");
    parameters.Add("sig", signature.ToString().ToLower());
    parameters.Add("v", "1.0");

    // Build the request string with the parameters above.
    StringBuilder requestParams = new StringBuilder();
    foreach (string key in parameters.Keys)
    {
       if (requestParams.Length != 0)
          requestParams.Append("&");

        requestParams.Append(key);
        requestParams.Append("=");
        requestParams.Append(System.Web.HttpUtility.HtmlEncode(parameters[key]));
    }

    // Build the request and write the parameters.
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = requestParams.ToString().Length;

    using (Stream writeStream = request.GetRequestStream())
    {
        UTF8Encoding encoding = new UTF8Encoding();
        byte[] bytes = encoding.GetBytes(requestParams.ToString());
        writeStream.Write(bytes, 0, bytes.Length);
    }

    // Get returned data.
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
        using (Stream responseStream = response.GetResponseStream())
        {
           using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8))
            {
                result = readStream.ReadToEnd();
            }
        }
    }

            return result;
}

The function gets the API key and the secret key as parameters and returns the raw XML response data, that looks similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<Auth_createToken_response
xmlns="http://api.facebook.com/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
THE_AUTH_TOKEN_GOES_HERE
</Auth_createToken_response>

Once I got the auth token, I needed the session ID. The session ID cannot be obtained if the user calling the method did not authorize the application. By that, I mean that once I have my application set up (the general configuration), when I navigate to the application page, I must grant it access to my data in order for this method to run. Without a session ID, I cannot call other data-retrieving methods.

Image lost since old blog

I can see the authorization page if I navigate to:

http://www.facebook.com/login.php?api_key=MY_API_KEY

The session ID is obtained using the same process as the one used to create the auth token. The only thing that changes is the set of parameters, and the signature (that is based on those parameters).

NOTE: Session IDs are not permanent. You will have to generate a new one upon the expiration of the current one in order to continue making API calls that retrieve user data.

The code for the session ID generation looks like this:

public static string GetSession(string apiKey, string secret, string authToken)
{
    string host = "http://api.facebook.com/restserver.php";

    string _signature =
        "api_key="
        + apiKey
        + "auth_token=" + authToken
        + "method=Auth.getSession"
        + "v=1.0"
        + secret;

    MD5 md5 = MD5.Create();
    byte[] init = Encoding.ASCII.GetBytes(_signature);
    byte[] hash = md5.ComputeHash(init);

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hash.Length; i++)
    {
        sb.Append(hash[i].ToString("X2"));
    }

    Dictionary<string, string> parameters = new Dictionary<string, string>();
    parameters.Add("api_key", apiKey);
    parameters.Add("auth_token", authToken);
    parameters.Add("method", "Auth.getSession");
    parameters.Add("sig", sb.ToString().ToLower());
    parameters.Add("v", "1.0");

    StringBuilder builder = new StringBuilder();
    foreach (string key in parameters.Keys)
    {
        if (builder.Length != 0)
            builder.Append("&");

        builder.Append(key);
        builder.Append("=");
        builder.Append(System.Web.HttpUtility.HtmlEncode(parameters[key]));
    }

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = builder.ToString().Length;

    using (Stream writeStream = request.GetRequestStream())
    {
        UTF8Encoding encoding = new UTF8Encoding();
        byte[] bytes = encoding.GetBytes(builder.ToString());
        writeStream.Write(bytes, 0, bytes.Length);
    }

    string result = string.Empty;
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
        using (Stream responseStream = response.GetResponseStream())
        {
            using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8))
            {
                result = readStream.ReadToEnd();
            }
        }
    }

    return result;
}

Notice the fact, that the previously generated auth token is used in this function.

Once I got the session ID, I can get the list of friends by using this code:

public static string GetFriends(string apiKey, string secret, string sessionKey)
{
    string host = "http://api.facebook.com/restserver.php";
    string callid = Convert.ToString(DateTime.Now.TimeOfDay);

    string _signature =
        "api_key="
        + apiKey
        + "call_id=" + callid
        + "format=XML"
        + "method=Friends.get"
        + "session_key=" + sessionKey
        + "v=1.0"
        + secret;

    MD5 md5 = MD5.Create();
    byte[] init = Encoding.ASCII.GetBytes(_signature);
    byte[] hash = md5.ComputeHash(init);

    StringBuilder hashString = new StringBuilder();
    for (int i = 0; i < hash.Length; i++)
    {
        hashString.Append(hash[i].ToString("X2"));
    }

    Dictionary<string, string> parameters = new Dictionary<string, string>();
    parameters.Add("api_key", apiKey);
    parameters.Add("call_id", callid);
    parameters.Add("format", "XML");
    parameters.Add("method", "Friends.get");
    parameters.Add("sig", hashString.ToString().ToLower());
    parameters.Add("session_key", sessionKey);
    parameters.Add("v", "1.0");

    StringBuilder builder = new StringBuilder();
    foreach (string key in parameters.Keys)
    {
        if (builder.Length != 0)
            builder.Append("&");

        builder.Append(key);
        builder.Append("=");
        builder.Append(System.Web.HttpUtility.HtmlEncode(parameters[key]));
    }

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = builder.ToString().Length;

    using (Stream writeStream = request.GetRequestStream())
    {
        UTF8Encoding encoding = new UTF8Encoding();
        byte[] bytes = encoding.GetBytes(builder.ToString());
        writeStream.Write(bytes, 0, bytes.Length);
    }

    string result = string.Empty;
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
        using (Stream responseStream = response.GetResponseStream())
        {
            using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8))
            {
                result = readStream.ReadToEnd();
            }
        }
    }

    return result;
}

The session key is obtained from the previous function. I will get an XML response with IDs of Facebook users who are my friends. These IDs are directly linked to user profiles. For example, I can view someone’s profile by navigating to http://www.facebook.com/profile.php?id=PROFILE_ID.


Back to posts