Integrating Facebook into SharePoint

As mentioned in my post Integrating Twitter into SharePoint I was recently faced with creating a stream from both Twitter and Facebook to display on a public-facing SharePoint website. While the Twitter experience was quite simple and enjoyable, that which was experienced when jumping across onto the Facebook side of the fence was far less so. In the end it actually wasn’t too difficult to implement, however the road there was full of potholes and speed humps.

My first stop was attempting to find an example of one which had already been implemented and the options were surprisingly limited. The closest I came was 3PillarLabs’ Facebook Webpart for SharePoint – Part 1 which looked like it would have at least given me the code samples I needed to get my own implementation working – if I was approaching it around the same time frame. The problem was that I continually (usually on the 2nd load) received an error: The remote server returned an error: (400) Bad Request. Viewing a number of recent comments on their code page seemed to indicate this was not just isolated to me.

The main issue was that in late December Facebook changed how their authentication tokens worked. You can read more about this both on Facebook’s own Removal of offline_access permission page and Randy Hoyt’s Changes to Facebook API: Access Tokens and offline_access. Long story short, 2 things seemed to now be the case – you couldn’t simply store a Facebook application code as per the example highlighted above because it seemed to last all of 2 minutes, and you couldn’t get a user token that would allow offline access which would never expire.

I was left with two options – I either needed to work with a page access token instead or refresh the user access token (which, after extended, would last up to 60 days). My original intent was to pull back Facebook statuses and unfortunately the page access token simply wouldn’t work for this purpose – I continually received the error (OAuthException – #102) A user access token is required to request this resource. Now this threw me off track a fair bit – as it turns out, you can actually use the page access token to retrieve a number of other things that would suit a similar purpose – namely feeds and posts. If you are happy with this approach you can skip the next paragraph and flick ahead, as this was how I finally implemented the solution.

It’s possible however that you may be faced with a situation where you need access to something that requires a user access token and therefore the brainstorming I did to solve this issue may still be of use. Essentially what I planned on doing was having a CustomAction in the SiteActions group which would make 3 calls – the first to access the application code via the URL


https://graph.facebook.com/oauth/authorize?client_id=CLIENTID&redirect_uri=CustomActionURL&scope=read_stream

the second to access a short-term user access token via the URL


https://graph.facebook.com/oauth/access_token?client_id=CLIENTID&redirect_uri=CustomActionURL&client_secret=CLIENTSECRET&code=CODE&scope=read_stream

and the third to extend the short-term user access token into a long (60-day) one via


https://graph.facebook.com/oauth/access_token?client_id=CLIENTID&client_secret=CLIENTSECRET&grant_type=fb_exchange_token&fb_exchange_token=USERTOKEN

This long term token would then be stored in a property bag and accessed by the web part. This process however would need to be run within every 60 days - it's possible you could instead use a timer job to automate that process.

Before continuing on it's important to point out that the CLIENTID and CLIENTSECRET values are easily retrieved similarly to how Twitter's were - all you need to do it sign in to the Facebook app development page and create a new app.

The final piece of the puzzle was to find an SDK to make life a little easier when programming against the Facebook API. Unfortunately, while SpringSource have a Facebook SDK for their Java framework, the ported Spring.NET equivalent for .NET (which I used for Twitter) did not. I ended up using the Facebook C# SDK for ASP.NET. Unfortunately though when using their code samples I ended up with an error as shown below: Dynamic operations can only be performed in homogenous AppDomain.

dynamic-operations

A little searching turned up that this occurs when trying to use dynamic properties with a web.config entry of <trust level="Full" legacyCasModel="true" /> - interestingly enough something Corey Roth pointed out was changed in SharePoint 2013 in his article New level of trust in SharePoint 2013 Preview. Rather than adjust that value which seemed fraught with danger (and was recommended against by one Microsoft employee, Humberto Lezama, in an MSDN forum post Getting SharePoint 2013 and MVC 4 to co-exist), I simply adjusted the code to work without dynamic properties.

The end result - finally - was a success.

facebook-feed

var oAuthAppToken = GetOAuthToken();
var client = new FacebookClient(oAuthAppToken);
var me = client.Get(FacebookId, new { fields = "posts.limit(10).fields(message,updated_time)" }) as IDictionary<string, object>;
var posts = (IDictionary<string, object>)me["posts"];
var data = (JsonArray)posts["data"];

List<FacebookStatusDisplay> statusDisplays = new List<FacebookStatusDisplay>();
foreach (var theStatus in data)
{
    var status = (IDictionary<string, object>)theStatus;

    if (status.ContainsKey("message"))
    {
        string message = (string)status["message"];
        string updatedTime = (string)status["updated_time"];
        statusDisplays.Add(new FacebookStatusDisplay(message, updatedTime));
    }

    if (statusDisplays.Count == 2) break;
}

if (statusDisplays.Count > 0)
{
    StatusRepeater.DataSource = statusDisplays;
    StatusRepeater.DataBind();
}
else
{
    FacebookFeed.Visible = false;
}

Note above that it is important to check for the message before trying to add the post, because we're not dealing with statuses directly it's possible that a message won't exist within the post.

string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials", OAuthClientID, OAuthClientSecret);
WebRequest request = WebRequest.Create(url) as HttpWebRequest;

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
    StreamReader reader = new StreamReader(response.GetResponseStream());
    string retVal = reader.ReadToEnd();
    oAuthToken = retVal.Substring(retVal.IndexOf("=") + 1, retVal.Length - retVal.IndexOf("=") - 1);
}

It's also worth noting that like the Twitter integration I used a SharePoint list for configuration, had the necessary error handling present and used the PrettyDate function identified to retrieve the correct time-lapsed date.

So overall with this knowledge at hand it would be relatively simple to knock out another web part which read posts from - importantly - a publicly accessible Facebook page. There were just so many little issues that had to be overcome to make this an enjoyable experience, namely the changes Facebook have made to their authentication. I feel for Facebook application developers and am glad this should be the extent that I need to interact with Facebook within SharePoint in the near future!

About these ads

One Response to Integrating Facebook into SharePoint

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: