Expanding Facebook Scope from a Force.com Social Application

If you’ve watched me and Chuck presenting the Social Sign On with Authentication Providers webinar, you might remember us demonstrating social sign on into a customer portal running on Force.com, and mentioning that the Auth Provider requests only the email permission from Facebook. We plan to allow customization of the list of requested permissions in a future release, but, right now, the only data available via the Facebook access token is the authenticated user’s email address and basic information such as name, gender, locale and the user’s friends list.

Preparing for a workshop I’ll be presenting in July at the Cloud Identity Summit in Vail, CO, I got to thinking about whether I could expand the set of requested permissions (in OAuth 2.0 terms, the requested scope) to allow code in a customer portal to do more interesting things with the Facebook Graph API, such as retrieve the user’s photos and videos, publish to the user’s stream, and so on. It turns out that, with a bit of help from the Facebook JavaScript SDK, it is indeed possible to request additional permissions. I’ve uploaded the complete code demonstrating this as a Gist; here’s a line by line dissection of the relevant JavaScript code.

First, we load the Facebook library and give it the div it needs. For simplicity, I’m loading the library synchronously:

<script src="https://connect.facebook.net/en_US/all.js"></script&
<div id="fb-root"></div>

Now I can set up the list of required permissions, split them into an array, and initialize a string with the list of permissions we’ll be requesting from the user:

    // Get required permissions from the controller
    var permissions = '{!permissions}';
    var permlist = permissions.split(',');
    var reqperms = '';

I’m getting a comma-separated list of permissions from the controller, since it knows which permissions it needs, but you could set up the permissions list directly in the JavaScript if you wanted.

Now it’s time to initialize the Facebook SDK using the Auth Provider’s consumer key (aka application ID), also retrieved from the controller:

    FB.init({appId: '{!appId}', xfbml: true, cookie: true});

That done, we can get the user’s login status. Note that, since the user already logged in via the Auth Provider, we don’t need to call FB.login(), but we do need FB.getLoginStatus() so that the SDK picks up the fact that the user did log in:

    FB.getLoginStatus(function(response) {

In the callback passed to FB.getLoginStatus(), we test response.status and, if the user is logged in and has authorized the Auth Provider, we query the /me/permissions Graph API node to get the list of permissions already granted to the Auth Provider:

      if (response.status === 'connected') {
        // Check we have the permissions we want
        FB.api('/me/permissions', function (response) {

It’s straightforward now to iterate through the list of permissions and build the list of permissions to be requested:

          for (var i = 0; i < permlist.length; i++) {
              if (! response.data[0][permlist[i]]) {
                  if (reqperms !== '') {
                      reqperms += ',';
                  }
                  reqperms += permlist[i];
              }
          }

If we do need any permissions, we use FB.login() to request them from the  user:

          if (reqperms.length > 0) {
            // We need some permissions - ask for them
            FB.login(function(response) {
              if (!response) {
                alert('Error getting permission!');
              } else {
                location.reload(true);
              }
            }, {scope: reqperms});
          }

And that’s pretty much it. I discovered in writing this sample that it is possible for the user to de-authorize the Auth Provider in Facebook while they’re in the portal in another browser window. This results in an HTTP error when the controller tries to access the Graph API using the user’s (now invalid, since it’s in the context of the app) access token. Take a look at the controller code to see how to easily handle this by catching the FacebookException.

As I mentioned above, we intend to support custom scopes in a future release, but this simple tweak allows much richer social applications on Force.com in the meantime. Try it out and let me know how it works for you via a comment.

Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • Anonymous

    Thanks PAT,
    For sharing nice article on FB and SFDC. Surely it will help to go ahead with Social integration of salesforce.

  • pooja pahwa

    Really very nice article..thanks Pat!!

  • vimarsh karbhari

    Thank you Pat, social integration is so important in today’s world!

  • Sachin Mittal

    I could not be able to get the following in controller code:
    String access_token = Auth.AuthToken.getAccessToken(‘What should come in this place’, ‘Facebook’);

    and how to access Facebook_ID__c from User as the user does not have this field.

    List users = [SELECT Facebook_ID__c FROM User WHERE Facebook_ID__c IN :friendMap.keySet()];

  • http://blog.superpat.com/ Pat Patterson

    Hi Sachin,

    The first argument to getAccessToken() is the auth provider ID – it’s listed first on the auth provider detail page. I added Facebook_ID__c as a custom field to the User object to be able to track users’ Facebook IDs. I set it in the auth provider’s registration handler like this:

    u.Facebook_ID__c = data.identifier;

    (I just updated the gist with the registration handler code)

    Cheers,

    Pat

  • Sachin Mittal

    I am getting an error: Error: Unknown property ‘String.id’ in my VF page
    Also object type FacebookUser is unknown in controller

  • http://blog.superpat.com/ Pat Patterson

    Hi Sachin – you need to install the Force.com Toolkit for Facebook to get FacebookUser etc – see http://wiki.developerforce.com/page/Getting_Started_with_the_Force.com_Toolkit_for_Facebook

  • Sachin Mittal

    Hi,
    I am still getting the same error as :Error: Unknown property ‘String.id’ in my VF page

  • http://blog.superpat.com/ Pat Patterson

    Make sure you re-save the controller and VF page. If you have the toolkit code in place, it should work now. Or, at least, it shouldn’t think ‘friends’ and ‘friendsInPortal’ are lists of strings.

  • Sachin Mittal

    Hi,
    Error accessing Facebook. Please logout of the portal and log back in.
    I am getting this exception as set in the controller class itself.
    I have used the portal handler developed by you as a template in SFDC org to get the Auth ID values in FacebookID__c.
    How to resolve this?

  • http://blog.superpat.com/ Pat Patterson

    You can modify the controller to display more detail on what is happening – add fbe.getMessage() to the displayed message. Are you getting anything back from Facebook – friends list? Photos? Can you post your code (controller + page) to a gist (https://gist.github.com) so I can look for errors?

  • Sachin Mittal

    Hi,
    Received 400 from https://graph.facebook.com/me/friends?access_token=null&fields=id,name,first_name {“error”:{“message”:”Invalid OAuth access token.”,”type”:”OAuthException”,”code”:190}}

    i have got this error about the invalid access token.
    I have not received any data as well.
    How to reset OAuth access token in facebook

  • http://blog.superpat.com/ Pat Patterson

    Looks like a logic error somewhere – access token should not be null.

  • Sachin Mittal

    Logic is correct but in the line:
    String access_token = Auth.AuthToken.getAccessToken(’0SO90000000PAtz’, ‘Facebook’);
    in the controller ’0SO90000000PAtz’ seems to be incorrect as this is the auth ID of my SFDC org which i have created using the Security Controls>Auth Providers.

  • http://blog.superpat.com/ Pat Patterson

    If the user logged in via that Auth Provider, and you have the Auth Provider Id correct (and it’s the Facebook auth provider), then I can’t see why that line would return null.

    What’s the URL of your gist page?

  • Sachin Mittal

    The gist URL is:https://gist.github.com/3180370

    Do you think the handler i have used as a registration handler in the SFDC Auth Provider settings could be the cause as the FacebookID__c. field needs to be populated with the user ID and it might not getting populated at the first place.

  • http://blog.superpat.com/ Pat Patterson

    Yes – if you are not populating the user’s Facebook_ID__c field in the reg handler, then that would cause an error – see my reg handler at https://gist.github.com/3018640#file_portal_handler.cls

  • Sachin Mittal

    Did you checked my gist code but changes according to my org auth provide ID.

    How to resolve the problem stated in the previous comment of Auth ID i am facing?

    The registration handler has to create a new portal user and contact with the account and profile how to implement this on SFDC org?
    Or can i use the template provided in SFDC itself for the same which can be selected in Security Controls>Auth Providers?