July 6th, 2010

BSS Classes :: Flash and the FB Graph

As was previously announced, our class library is available on GitHub. Our first installment explaining how we use some of these classes deals with one of the most recent additions to the library – OAuthBridge.

One of the most important concepts philosophically to our approach is that we don’t declare the “best” or “right” way to do something, even for our own devs. Instead, we provide mechanisms that allow a dev to choose for themselves the best approach a specific project. There’s no better example of that than Facebook, where something as simple as the way you house content can become a heated debate. One thing is for sure though – we love the expressiveness technologies like Flash provide, and we wanted to be sure we could provide rich, beautiful games & experiences without trying to impose a specific preference.

OAuthBridge takes the most complicated part of Facebook and Flash – logging a user in and remembering them – and wraps it into a few easy lines of code. It does this without imposing how you build your application. It doesn’t care how you choose to build your Facebook app or what environment it’s in. It aims to eliminate the entire AS3 Facebook API down to a single method – login.

Stephen (@skoch) and I have spent a long time wrapping our head around all the different ways Flash can connect to Facebook and all the different authentication traps you can fall into. What we’ve done is simplified Facebook to a couple of lines of code, a snippet or two of PHP or JavaScript and a few events.

Our OAuthBridge looks to resolve five simple issues:

 

    1. Provide an easy mechanism to log in, log out and authenticate from Flash.

 

  • In the case of offsite applications, leverage the fact that the access token Facebook provides is persistent, so users log in one time and never even have to click login again – they come to the site and they’re already in.

 

 

  • In the case of Facebook-based applications, provide an easy flow for both FBML and IFrame based applications that streamlined the authentication process.

 

 

  • Allow developers to test real Facebook API calls without leaving the Flash IDE.

 

 

  • Build all of the above in a way so that Flash would never need hard coded info about the specific application we’re using. It’s passed the application ID and all the relevant information and make calls from there.

 

 

Rigging up your ActionScript

Regardless of the environment our application lives in, we’ll start with the Flash side. Let’s begin by importing the major classes we need to run the bridge:

import com.bigspaceship.api.facebook.OAuthBridge;
import com.bigspaceship.api.facebook.FacebookPermissions;
import com.bigspaceship.events.FacebookAuthEvent;

OAuthBridge wraps the login procedures for the different Facebook environments into a single method, aptly named login(). It stores a public variable session of type OAuthSession when the user logs in. OAuthSession basically wraps all of the session information Facebook passes back to us when a user authenticates with our app – the access token, uid, secret and so on. It also keeps track of what permissions the user has allowed for our app. We can call myOuthSession.hasPermission(“facebookPermissionString”); and we’ll get back true if the user allowed us that specific permission, false if not. As a convenience we’ve mapped all the possible permissions as constants in the FacebookPermissions class, or you can read about ‘em here.

OAuthBridge dispatches FacebookAuthEvents as necessary. Our events are LOGIN, LOGOUT, LOGIN_CANCEL, LOGIN_PROCESS_START and LOGIN_PROCESS_COMPLETE.

In five lines of code we can have a bridge ready to connect to Facebook. It’s as simple as this:

_bridge = new OAuthBridge();
_bridge.addEventListener(FacebookAuthEvent.LOGIN,facebookOnLoginHandler);
_bridge.addEventListener(FacebookAuthEvent.LOGIN_CANCEL,facebookOnLoginCancelHandler);
_bridge.addEventListener(FacebookAuthEvent.LOGOUT,facebookOnLogoutHandler);
_bridge.initialize(stage.loaderInfo);

The initialize method will check the loaderInfo parameters (flashvars) to see if the session variable is set. If so, we know that the user has already authorized the app we can immediately create the OAuthSession object and dispatch the LOGIN event. Otherwise it immediately dispatch the LOGOUT event, so we can set up our login button.

Let’s assume that our user hasn’t logged in yet and we have a button on the screen that allows them to do so. When clicked, all we need to do is:

// a comma deliminated string of all the permissions you want to ask for.
var options = { perms: FacebookPermissions.PUBLISH_TO_STREAM + ',' + FacebookPermissions.USER_PHOTOS };
_bridge.login(options);

This will ask the browser to launch the appropriate Facebook authentication model. For example, in an Open Graph enabled site a popup window will appear asking the user to log into Facebook and once done, our OAuthBridge will dispatch that same LOGIN event mentioned above. If the user cancels logging in, we’ll get the LOGIN_CANCEL event instead. Assuming they log in successfully, we can access any information about the user’s session via:

_bridge.session;

So for example, the logged in user’s uid is:

_bridge.session.uid;

OAuthBridge also allows provides a mechanism to log users out, but it only works with Open Graph apps that don’t live on Facebook (formerly known as Facebook Connect apps).

_bridge.logout();

The other two FacebookAuthEvent methods, LOGIN_PROCESS_START and LOGIN_PROCESS COMPLETE are for when we just want to know that the user clicked login and then closed the prompt. Whether they logged in or not is irrelevant. These are useful when you write classes that just want to be aware that the user is trying to connect with Facebook without worrying about the result, such as a shield that prevents clicks while the user deals with the authentication prompt window.

Handling the different authentication flows

As mentioned before, there are three fundamental places OAuthBridge deals with the authentication flow.

 

    1. Facebook application using an IFrame

 

  • Facebook application using FBML

 

 

  • Open Graph API enabled site (residing outside of facebook.com)

 

 

(Technically there’s a fourth – Facebook applications inside an FBML tab on a fan page -but we’re still testing that flow. we’ve got it covered in the FBML section below.)

Each has it’s own way of logging a user in and getting permissions back to the app. There are any number of reasons for using IFrame or FBML or Open Graph apps, and those could be debated another day (In fact, Facebook has an entire page dedicated to the subject). The good thing about OAuthBridge on the Flash side is it handles both without any changes whatsoever. Since each environment requires a different flow, we’ve created complimenting JavaScript and PHP services to connect to OAuthBridge.

Oh… if anyone out there wants to port our PHP services to other languages, we’ll be happy to update with links.

I scream for IFrames

Demo | Source

In the case of an IFrame, this Authentication flow will open a popup window which will prompt the user to authorize your app after which will close (IE excluded) and pass the session back to Flash using simple JavaScript.

To start with, we’ll need to include the JavaScript in the head of our page:

<script src="oauthbridge_iframe.js" type="text/javascript" charset="utf-8"></script>

Embed your SWF in the body of your tag as you normally would — we recommend SWFObject — and be sure to set the allowScriptAccess parameter to “always”. To be sure we are targeting the SWF properly from OAuthBridge, make sure we set the id. In JavaScript:

com.bigspaceship.api.facebook.OAuthBridge.setSwfId('yourSwfId');

When Facebook hits our index.php file, it passes session information in a query string (if the user is already signed in and authenticated). What we’ll do is convert that into a sanitized session that JavaScript can then pass along to Flash. This will get to our OAuthBridge, which will effectively immediately dispatch the LOGIN event described above. Summed up: Any returning user to your app will automatically get logged in on the Flash side.

$session = '';
if( isset( $_GET["session"] ) )
{
    $session = urldecode( $_GET["session"] );
    if( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE') )
    {
        $session = htmlspecialchars( $session );
    }
}

If this variable exists, we know the user has already authenticated with our app and can pass it right along to flash using flashvars. If it doesn’t,

// this gets passed in with our SWFObject embed
var flashvars = {
    popUpsAllowed: true,
    fb_type: "popup",
    fb_environment: "iframe",
    fb_app_id: "yourAppId",
    fb_redirect: "http://apps.facebook.com/appname/iframe_popup.php",
    session: '< ?php echo $session; ?>'
}

Beyond the session variable, you’ll notice four additional variables we will be using to drive OAuthBridge.

 

    • fb_type: This is the ‘type’ of authorization page facebook will give you. The choices here are; page, popup, wap or touch. For this example, we are going to choose popup.

 

  • fb_environment: This is the render method you’ve set for your facebook app (FBML/iframe) from the application’s settings on facebook.

 

 

  • fb_app_id: This is your Application ID

 

 

  • fb_redirect: This is the page which facebook will direct the user after they have authorized. We’ll come back to it in a moment.session: Jackpot. The session variable as supplied by facebook (if it exists).

 

 

If our session var covers users who have *previously* authenticated with the app, fb_redirect covers users who *haven’t*. In that scenario, our OAuthBridge will dispatch a LOGOUT event immediately. We’ll know we need to provide the user with some sort of button to click that will call the login method, which will open a popup window at the URL fb_redirect specifies. This popup will authorize the user, communicate back to our oauthbridge_iframe.js file which will pass the login info to your OAuthBridge instance which will fire the LOGIN event. Bam, just like that, your application is now ready to make calls to the graph API. And of course, the next time the user visits your application OAuthBridge will receive the session immediately.

So while this flow sounds incredibly complicated, all you’ll need is two PHP scripts, a JavaScript file and the five lines of code described at the top of the page.

A FLDSMDFR for FBML

Demo | Source

The biggest difference between authenticating for FBML and IFrame is in terms of user experience — we have to authenticate in the same window. The downside to this is that users will leave Flash, authenticate and then be returned back — meaning the Flash has to reload and reinitialize. In terms of setup, it’s quite similar — We will be passing in the same flashvars we used above. In our example we’re again using PHP to set up, except this time rendering FBML instead of HTML and JavaScript. Here’s what our index.php file looks like:

<script type="text/javascript">// <![CDATA[
 
// ]]></script>
 
&lt; ?php
 
    $fb_type = "page";
    $fb_environment = "fbml";
    $fb_app_id = "yourAppId";
    $fb_redirect = "http://apps.facebook.com/appname/fbml_redirect.php";
 
    echo "";
?&gt;

The only major change here is with fb_redirect. All it does is redirect back to the main app. This is really much more for aesthetic reasons than anything else — our redirect removes all the excess query information Facebook passes along, leaving a user with a nice simple URL to love and remember. The essence remains the same as the IFrame though. A user gets authorized one time via fb_redirect, and forever more when returning automatically has a session variable passed in via Flashvars. Same LOGIN and LOGOUT events, same login method in OAuthBridge.

Note that you’ll need to make sure you have the “Canvas Session Parameter” set to enabled in your Application Settings on Facebook, so the session variable gets passed in.

UPDATE: We’ve tested the flow inside of an FBML tab. If you wanted to provide a user the full functionality of your application on their page (or a fan page), most of the above works pretty well. There are just a few things you have to keep in mind:

 

    1. In certain cases you may want to set your application to redirect back to a specific tab, rather than the app itself. For example, we’ve done a few apps for brands where the application page itself is never used by the user. Instead, they interact entirely on the tab.

 

  • There are some issues with the FBJS bridge connecting properly on the tab. Because of this, you’ll have to get a little tricky and recreate the functionality. Something like this will work fine:

 

 

<script type="text/javascript">// <![CDATA[
 
// ]]></script>&lt; ?php
		// sk: we often pass this in to use for loading assets, etc
		$deployPath = "http://www.domain.com/labs/YOUR_APP_NAME/";
 
		$fb_type = "page"; // the 'type' of authorization (page, popup, wap, touch as described: http://developers.facebook.com/docs/authentication/)
		$fb_environment = "fbml"; // the environment you've set for your facebook app (FBML/iframe)
		$fb_app_id = "YOUR_APP_ID"; // your facebook app id
		$fb_redirect = "http://apps.facebook.com/YOUR_APP_NAME/fbml_redirect.php"; // the redirect for this flow
 
		echo "";
	?&gt;<script type="text/javascript">// <![CDATA[
	function changeCSS(){
		document.getElementById('feature').setStyle('display', 'block');
		document.getElementById('start_img').setStyle('display', 'none');
	}
// ]]></script>

Basically this creates a splash image that when clicked injects the fb:swf tag in it’s place. Everything else works exactly the same. You can download example files of this here.

Forging ahead with Open Graph

Demo | Source

Open Graph applications that don’t live on Facebook are very similar to IFrame apps mentioned above, in that we’ll be using JavaScript as a middle man between Flash and Facebook. In fact, all we need is JavaScript. No additional PHP is necessary.

The first thing you’ll want to do is grab the Facebook JavaScript SDK and make sure it’s embedded on your page. Facebook recommends using the asynchronous method for embedding this SDK, however as of this writing we found it much more stable using the synchronous way. To do that, immediately underneath your body tag write:

<script type="text/javascript" src="http://connect.facebook.net/en_US/all.js"></script><script type="text/javascript">// <![CDATA[
  FB.init({
    appId  : 'YOUR APP ID',
    status : true,
    cookie : true,
    xfbml  : true
  });
// ]]></script>

The rest is almost exactly like the IFrame example, with a different script added to the head tag.

 

And again like the IFrame, immediately after your embed your SWF (again, we recommend SWFObject) add the following line of JavaScript code:

com.bigspaceship.api.facebook.OAuthBridge.setSwfId(‘yourSwfId’);

This will tell the OAuthBridge what SWF to communicate with. When you call the login method, a popup prompt will appear asking the user to authenticate and once done so, that information will get passed into Flash. If the user has previously authenticated, that session will automatically get passed into Flash and OAuthBridge will proceed as normal.

Debugging Facebook Calls without the Browser

Regardless of the environment you’re building for, one pain point of Flash development with Facebook has always been the inability to make calls from a debugging environment like the Flash IDE or Flash Builder. We’ve resolved this by allowing you to pass in an optional parameter to the OAuthBridge constructor – an OAuthSession object you generate manually.

What we’ll want to do is initiate the Facebook authentication sequence using our browser – we only need to do this one time, assuming we don’t deauthenticate the app – and console.log or javascript alert all the session information. After that, simply generate the OAuthSession in Flash and pass it to the constructor of the OAuthBridge.

 // in flash
var sessionObj:Object = {};
sessionObj.access_token = "yourAccessTokenGoesHere"
sessionObj.expires = 000000000;
sessionObj.secret = "yourSessionSecretGoesHere";
sessionObj.session_key = "yourSessionKeyGoesHere";
sessionObj.sig = "yourSigGoesHere";
sessionObj.uid = "yourUidGoeshere";
 
var permissions:String = ""; // fill out all the permissions you know you have authenticated with.
 
var debugSession:OAuthSession = new OAuthSession(sessionObj);
 
_bridge = new OAuthBridge(debugSession);
_bridge.setPermissions(permissions);

Now when we call _bridge.login it will immediately fire the LOGIN event and use our debug session. All our API calls should work.

Some example API Calls

Communicating with Facebook in Flash is a breeze from here. Want to load a user’s basic information?

var req:URLRequest = new URLRequest("http://graph.facebook.com/" + _bridge.session.uid + "/");
 
var profileRequest:URLLoader = new URLLoader();
profileRequest.addEventListener(Event.COMPLETE,profileRequestLoadedHandler);
profileRequest.load(req);
 
function profileRequestLoadedHandler($e:Event):void {
trace($e.target.data); // decode this json using adobe's corelib.
}

How about loading a user’s profile photo?

var req:URLRequest = new URLRequest("http://graph.facebook.com/" + _bridge.session.uid + "/picture/?type=small");
 
var con:LoaderContext = new LoaderContext();
con.checkPolicyFile = true;
 
var pictureLoader:Loader = new Loader();
pictureLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,pictureLoaderCompleteHandler);
 
pictureLoader.load(req,con);
 
function pictureLoaderCompleteHandler($e:Event):void {
addChild(pictureLoader);
}

Maybe we want to add to the user’s wall? The big key here is to remember to request from https, not http. Our URL is https://graph.facebook.com/[uid]/feed. We’ll need to pass that access token as a GET variable and whatever we want to post to the user’s wall as POST.

var vars:URLVariables = new URLVariables();
vars.message = "This is a test message.";
 
var req:URLRequest = new URLRequest("https://graph.facebook.com/" + _bridge.session.uid + "/feed/?access_token=" + _bridge.session.access_token);
req.method = URLRequestMethod.POST;
req.data = vars;
 
var streamRequest:URLLoader = new URLLoader();
streamRequest.load(req);

With this new API connecting and building has never been easier, or more fun. I no longer dread having to write complex Facebook applications. On the contrary – I look forward to making expressive, interesting stuff for users there. You can read more on the full breadth of the API at http://developers.facebook.com/docs/api.

  • http://www.facebook.com/profile.php?id=584918867 Roderick Peace

    Have you guys updated this stuff this year?