Advertisement

Authenticating Users With Facebook Connect and Google Friend Connect

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

Most social networks have API tools that allow almost any website to authenticate users through their system. In today's tutorial, we will learn how to use these tools. Using a simple comment model, users will learn how to leave a comment within their Facebook or Google profiles.

The Application

Briefly, I will go over the demo application. I have a very simple, static HTML page that shows a photo and allows the user to comment on it. In a real application you would probably save the comments to a database, but for the sake of demonstration I just save them to a text file with each line representing a new comment. This code isn't particularly important until you get to the add comment form.

# index.php
...
<div class="new-comment">
  <h2 class="sub-title">Add A Comment</h2>
  
  <form action="php/savecomment.php" id="comment-form" method="post">
    <div id="userbox" style="display:none;"></div>
    
    <div id="userinfo">
      
      Name: <input id="name" name="name" type="text" />
      <input id="url" name="url" type="hidden" />
      <input id="image" name="image" type="hidden" />
      
    </div>
    
    <div class="comment">
      Comment:<br />
      <textarea id="comment" name="comment"></textarea>
    </div>
    <input type="submit" value="Send Comment" />
  </form>

</div>
...

Here you see we have a basic form with four fields: name, url, image, and comment. I chose to hide the url and image fields because this is data we will get from Facebook and Google Friend Connect. The form is submitted to a PHP file, savecomment.php, which I won't go over but is included in the download. In essence it takes all the post data and stores in an existing comments data file with pipe, "|", characters separating each field. Again, not a practical technique but sufficient for our purposes. A little above the form we list out all the comments in that file by including another PHP script, readcomments.php.

# index.php
...
<div class="comments">
  <h2 class="sub-title">Comments</h2>
  
  <?php include("php/readcomments.php"); ?>
</div>
...

One last piece of code we need to look at is the JavaScript includes. All of our authentication is done on the client side, so I created application.js to hold the code responsible for that, and to save myself from writing too much JavaScript I included jQuery (via Google).

# index.php
---
<head>
...
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
  <script src="./js/application.js" type="text/javascript"></script>
</head>

Updating The Page to Show User's Information.

After creating this we can move into the application.js file mentioned earlier. I decided that it would be best to create a function for each service that wrapped all the logic required in authentication. Then, after creating these for both services I extracted out common code to keep the code concise. After creating the file declare a function called update_userbox()

# application.js
---
//Generic updates #userbox with info retrieved
//from services
function update_userbox(name, image, url, logout) {

  //populate the data in #userbox and show it
  $('#userbox').html( "<a href='"+url+"'>"
                    + "<img alt='"+name+"' src='"+image+"' />"
                    + "Logged in as " + name + "</a> "
                    + "(<a href='./index.php' onclick='" + logout + "'>logout</a>)" ).show();

  //hide name input and service
  //login buttons
  $('#userinfo').hide();


  //populate the values of the inputs
  //using data from service
  $('#name').val(name);
  $('#url').val(url);
  $('#image').val(image);

}

This function is generic and can be used with either service, and as more spring up could probably be used in others as well. The purpose of this is to insert HTML into an empty div called #userbox so the user has a visual understanding that they logged into a service. This is done by hiding the name box, and showing a profile image from the remote service along with their name and a logout link to disconnect from the service. Also behind the scenes we fill in the name, url, and image inputs so they are submitted to the server along with the comment for saving to our database file. You can see this is done by passing in four variables:

  • name: the user's name they provided to the service
  • image: a url to the user's profile image
  • url: a url to the user's profile on the service
  • logout: a string of JS code to execute when logout is pressed

These are all pretty straightforward, except the logout variable. This can be explained when you look at the APIs that FB and GFC offer. Each has function that will notify the service that the user wishes to be logged out, this is how I chose to pass that function call into the logout link.

Facebook Connect - Getting Your API Key

We will start with Facebook Connect. The first thing we will need to do is create an application on Facebook's Developers site. It seems a bit odd at first that we have to create a Facebook application for this, but as far as I can tell it is only to receive the API key and to register your URLs with their developer program.

After you have created the application we need to edit some settings, on the left side of the screen you will see tabs, click on Connect. Here you need to enter the Connect URL which is the URL where the root of your site exists. I also chose to upload a picture, and I recommend all websites do this as it gives you some visual branding.

Alright now you can save these changes and it will take you to the application summary page. Here is where we can find the application API key, so go ahead and copy that on to your clipboard.

Adding A Cross-Domain Receiver

Facebook architected their connect API to work entirely on the client side. This tutorial will require no server side code to authenticate users. This is done through some intricate AJAX techniques where Facebook passes data back and forth via iframes to circumvent the same-origin policy implemented by most browsers. Part of this process requires that we place a file on our server that Facebook can interact with to verify our identity. So at the top-level of your domain create a file called xd_receiver.html and insert this code.

# xd_receiver.html
---
<pre name="code" class="html">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
    <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
</body>
</html>
</pre>

The Facebook Connect Button

Facebook requires us to jump through a few hoops to get everything working, first of which is we need to include a JS file from the Facebook website and run the init() function in our index.php file at very bottom just above the closing </body> tag.

# index.php
---
<!-- Facebook API Includes -->
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>
<script type="text/javascript">
  FB.init("FB_API_KEY", "xd_receiver.htm", {"ifUserConnected" : auth_using_fb});
</script>

There are a few things we need to look at in this function. First, be sure to replace FB_API_KEY with your API key. Next we have a string representing the path to our cross-domain receiver file which should be at the root of your application directory. Finally, we can pass in a hash of options. We want to maintain users' login state so we tell Facebook to run a function auth_using_fb (we will create this in a few moments) if the user is already connected to our site. This means that if the user reloads the page it will still show them as logged in so they don't have to re-login on every page.

Next we have to create the actual login button, this requires using XFBML, Facebook Markup Language which is an extension to HTML. The X denotes code that is inserted on 3rd party websites and not on Facebook's website. Somewhere on the page we have to insert the tag Fb:login-button and a few options.

  <fb:login-button length="long" onlogin="auth_using_fb();"></fb:login-button>

I chose to put this next to my name textbox so the user could easily see it when they go to add a comment. Notice we have two attributes length and onlogin. Length allows us to specify the text on the button and has two options: short (the default) and long. Short says Connect and long says Connect with Facebook. Onlogin works a lot like onclick or onmouseover and allows us to execute JS when the user successfully authenticates with our site through Facebook. We call the same function we mentioned earlier, auth_using_fb(), but before we can create that we need to make one more change. At the top of the page in the HTML tag we need to tell the browser we are using more than one markup language.

# index.php
---
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">

The xmlns attribute specifies the xml namespace for the document. The first is the standard xhtml, and the second is the new facebook markup language, this helps make our document W3C compliant.

Writing the Javascript

Now we are going to go back to application.js and write the auth_using_fb() function.

# application.js
---
//Facebook Connect
function auth_using_fb() {
  //get the users data from FB
  var viewer  = FB.Facebook.apiClient.fql_query(
  
      'SELECT name, pic_square_with_logo,profile_url FROM user WHERE uid='+FB.Facebook.apiClient.get_session().uid,
      
      function(results) {
        update_userbox( results[0].name,
                        results[0].pic_square_with_logo,
                        results[0].profile_url,
                        'FB.Connect.logoutAndRedirect("./index.php");return false;')
      }
  );
}

This is the function we use to interface with Facebook's data, and retrieve users' data. The login button we created earlier actually has the functionality for signing the user into Facebook built-in, but if want to grab the information about the user we must request it separately. The first line of code in the function is a call to the Facebook API method, fql_query(). This function allows us to use Facebook's SQL like query language to fetch the user's data. We only need the three columns we discussed earlier: name, picture, and url. The Facebook Developer wiki has a page containing all the various tables that you can query for information. It is important to add the WHERE clause that limits to the currently logged in user. The second parameter of fql_query is a callback function that is passed an array of the results. We just need to take the first result in the array and send each property to our update_userbox() function along with the logout JS call. It is important to include "return false;" after the logoutAndRedirect() call because otherwise it causes the page to reload before the API can log out the user.

And amazingly that is all we need to do for Facebook Connect to work, go ahead and try it out!

Google Friend Connect - API Key

Much like Facebook Connect, Google Friend Connect requires us to sign up for an API Key. This is far quicker than Facebook Connect as they have an easy-to-use wizard that walks you through it all. First you need to provide the application name and URL just like in Facebook Connect.

Next it instructs you to upload a few files to your server for cross-domain AJAX support, again just like Facebook Connect. Seeing a trend here?

The final step will verify that everything is setup properly. Google calls the API Key the Site ID, but it acts the exact same Facebook's API key.

Including the Necessary Files

Next we need to include the proper JS files at the bottom of our page after the Facebook files. We also need to implement the initOpenSocialApi() method of the Google Friend Connect API. This takes one parameter in the form of a hash of options. The only required option is site which is our Site ID we collected earlier.

# index.php
---
<!-- Google API Includes -->
<script src="http://www.google.com/friendconnect/script/friendconnect.js?v=0.8" type="text/javascript"></script>

<!-- Initialize the Google Friend Connect OpenSocial API. -->
<script type="text/javascript">
  google.friendconnect.container.setParentUrl('/envato/nologin/' /* location of rpc_relay.html and canvas.html */);
  google.friendconnect.container.initOpenSocialApi({
    site: 'GFC_API_KEY',
    onload: function(securityToken) { auth_using_gfc(); }
  });
  google.friendconnect.renderSignInButton({id:"google-login",style:'long'})
</script>

We also need to page in a callback function to execute when the user is authenticated with Google Friend Connect. Additionally we have to call a function that renders the sign in button, this is very similar to the XFBML markup we used earlier except Google decided to stick with plain HTML. This function requires we pass it a DOM id of the element we want the signin button to be created in, I made a div just below the FB login button with an id of google-login. We also pass in the style:'long' option so that it is similar to our Facebook button.

<div class="services">
  <fb:login-button length="long" onlogin="auth_using_fb();"></fb:login-button>
  <div id="google-login"></div>
</div>

Writing the JavaScript

Google Friend Connect is similar in many ways to Facebook Connect, which of course makes our job all the easier. One language difference I found is that Google's API tends to be a bit more verbose in nature so we will split our explanation of auth_using_gfc() into two parts.

//Google Friend Connect
function auth_using_gfc() {
  //Request GFC to send extra profile data
  var params = {};
      params[opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS] =
      [opensocial.Person.Field.URLS];


  // Create a request to grab the current viewer.
  var req = opensocial.newDataRequest();
  req.add(req.newFetchPersonRequest('VIEWER', params), 'viewer_data');
...

The first thing we do is declare the params variable as an empty hash. This will contain the options we need to send with our request to Google, because by default we do not receive the user's profile URL. Next we create a request object that will actually make the request to Google for the user's profile data. The add() method takes two arguments a newFetchPersonRequest() object and then a unique string to identify the data. VIEWER is a constant representing the currently logged in user.

// Sent the request
req.send(function(data) {

  // If the view_data had an error, then user is not signed in
  if (!data.get('viewer_data').hadError()) {
    //get the users data from GFC
    var viewer = data.get('viewer_data').getData();
    
    update_userbox( viewer.getDisplayName(),
                    viewer.getField(opensocial.Person.Field.THUMBNAIL_URL),
                    viewer.getField(opensocial.Person.Field.URLS)[0].getField('address'),
                    'google.friendconnect.requestSignOut()' );
  }

});

The last part of the function is the actual request for data, using the send() method which takes one argument of a callback function. We declare the function inline and we have an if statement that checks weather the request received an error. If it doesn't we assume everything went alright and we declare a variable called view that holds the data received from the request. This data is then passed into our update_userbox() function. The only thing to note here is the the third argument that passes in the user's URL. Google allows users to enter multiple profile URLs (such as Facebook, Twitter, etc.) and we only need the first one which is the Google profile URL. The final argument is our string of JS to execute that signs the user out which also reloads the page.

This is all we need to do, so go ahead and try it out! One really nice thing you'll notice is that user's don't have to have a Google account to login they can also use their AOL/AIM, Yahoo!, Netlog, or Open ID accounts.

Conclusion

While this specific example is not production ready, hopefully you can see how easy it would be for us to implement this into our existing applications. I encourage everyone to take a good look over the documentation Facebook and Google offer.

I hope you enjoyed this tutorial, and if there is enough interest, I will write a follow-up tutorial on how this can be further integrated using PHP on the server-side. As always, if anyone needs help or you can find me on Twitter, @noahhendrix.


Advertisement