Wednesday, November 28, 2012

ApplicationCraft - Easy oAuth

Overview

This is one of a series of blogs I'm writing as I build Easy Peasy Task List.  If you want to know about the other related blogs, visit Status of discovery / learning exercises.

ApplicationCraft provides an easy way to authenticate users via 3 social networks: Twitter, Facebook and Dropbox.  The code required to authenticate is quite easy and is documented as shown below.  The oAuth overview docs are located here: http://www.applicationcraft.com/developers/documentation/product-guide/advanced-features/oauth/

Web app only for now

At this time (November 28, 2012) the native app doesn't work.  There is a good thread about oAuth in the forum:  https://getsatisfaction.com/application_craft/topics/oauth_has_arrived and CTO Joe Moss updated it yesterday that a ChildBrowser plugin will be required.  So until that is done, this demo only works as a web app.

Video

I've created a short video that shows how this demo is coded and what properties are setup.


Code

The exported project is available from my github account: https://github.com/bartonhammond/TaskList.  Just clone the repository or download it as a zip.  Then within ApplicationCraft, import the "app_Step%2B1%2B-%2BOauth_r55.acft".  You will have to follow the steps below to obtain the key/secret data values from each of the social networks and enter their values in the application properties (see below).

Web app

You can kick the tires here:  http://acft.ws/nftc.  

Steps to getting the social networks key/secrets.

The first step required is to get the key/secret data from the social network.  The following links should suffice:




Now let's look at the code from this demo

Let's follow what happens when the dropbox image is clicked.  The logic is similar to facebook and twitter.
/**
 * Handle twitter
 */
function handler_twitterImg_onClick(mouseev){
    window.oauth='twitter';
    doOauthSignIn();
}

When the twitter image is clicked we call this function.  The first thing is to set a global variable I've called "window.oauth".  This is made global so that it can be accessed later within the callback function.  I needed a way to determine which social network was been accessed.  All three image handlers set the window.oauth variable appropriately and call doOauthSignIn().
/**
 * Generic oauthSignIn
 */
function doOauthSignIn() {
      app.oAuthSignIn(window.oauth, authCallback); 
}
This doOauthSignIn does only one thing - it calls the app.oAuthSignIn passing the window.oauth variable and the function name to be called when the oAuth process completes. The docs are here: http://www.applicationcraft.com/developers/documentation/product-guide/advanced-features/oauth/authentication2/

The function authCallback is shown below.
/**
 * Callback from SSJ when oAuth is completed
 * 
 * If result is good, make a request to the social network
 * for identifying information for the user
 */
function authCallback(result, userAuthKey) {
    if (result) {        
        app.callSSJ('makeOAuthRequest', function(error,data){
            setFields(data);
        }, [userAuthKey,window.oauth]); 
    }
    else {
        alert("failed oauth");
    }
}
The function authCallback is called when the social network completes the authentication of the user. The parameters provided to this function are defined in the ApplicationCraft.com documents http://www.applicationcraft.com/developers/documentation/product-guide/advanced-features/oauth/authentication2/

Note that the object returned in the function defined on line 9 "data" will be the data returned by the SSJS function "makeOAuthRequest".  If you look below you'll see that the SSJS function builds that data object and handles the discrepancy of the returned data that the three social networks return.  This makes the code on the client side easy as it doesn't have to multiple callbacks, one for each social network.  Instead the SSJS function handles that abstraction by returning a normalized object.

If the result of the social network oAuth process is successful, we make a call to a server side javascript (SSJS) function called "makeOAuthRequest".  Note that we are passing two parameters to this function: userAuthKey and window.oauth.

The SSJS function makeOAuthRequest is shown below:
/**
 * param: userAuthKey - what was provided during the oAuth
 *        source - what social network is being accessed.
 * 
 * Make the oAuthRequest and return the data.
 * 
 * The three sources are facebook, twitter and dropbox.
 * 
 * The fields object below has the request for each source and what the data attribute 
 * name is that is returned.
 */
function makeOAuthRequest (userAuthKey, source) {
  
    var fields = {'facebook' : {request: 'https://graph.facebook.com/me', id: 'id', name: 'name'},
                 'twitter'  : {request: 'https://api.twitter.com/1.1/account/verify_credentials.json', id: 'id', name: 'name'},
                 'dropbox'  : {request: 'https://api.dropbox.com/1/account/info', id:'uid', name:'display_name'}};
       
    var data =  ssj.oAuthRequest(userAuthKey,
            fields[source].request, 
            'GET',{});    
           
    return {id: data[fields[source].id], name: data[fields[source].name], source: source};
   
}
This function has some objects that need explanation.

lines 14-16

This is an associative array indexed by the social network source.  There are three array entries which are indexed by facebook, twitter and dropbox.  Remember that the client is calling this SSJS function passing in the global variable window.oauth.  If you index this array by the source variable you return a object.  The object has three fields: request, id and name:

  • request field is the URL that is used in the oAuthRequest to return information about the currently logged in user
  •  id: this is the value in the returned data (line 18) that contains the value I'd like to track, namely the id within the social network.
  • name: this is the value in the returned data (line 18) that contains the value of the logged in persons name.  For facebook and twitter, the value is "name".  But for dropbox the value is "display_name".

lines 18 - 20

This single call, by utilizing the fields array, supports accessing all three social networks.  On line 19 the request value for the selected source is used.  To read this line 19, index into the fields array using the "source" value and then access the value of the request attribute.  So if the source is "facebook" the request will be 'https://graph.facebook.com/me'

line 22

This line returns an object with three attributes: id, name and source.  The id value is taken from the social networks returned data.  By indexing into the fields array, again, with the source, the value within the data object is retrieved by referencing the field with the value of the id.  For twitter and facebook, that value is "id".  But for dropbox, data.uid is what is retrieved.  Likewise, the name is retrieved by referencing the value of the "name".  For twitter and facebook, it's "name" while dropbox the attribute is "display_name".

Summary

I think ApplicationCraft.com has done a great job in making oAuth easy for these three social networks.  Hopefully the code presented here will help you learn how to incorporate oAuth into your application.