Facebook IFrame applications and the new Open Graph API

Facebook has long recommended that platform applications are developed using IFrames instead of FBML. Unfortunately, that has typically been a painful endeavor. Facebook has passed session information to the user as parameters on the first request to the iframe. The developer was required to store that information in a cookie if they wanted to persist it. Unfortunately, webkit based browsers (notably Safari and Chrome) don’t allow cross domain cookies by default. This has caused some painful workarounds. Inside, I’ll show you a painless one.

To workaround the cross domain cookie problem, we’ll need to get our application out of the iframe. A typical Facebook connect login button looks like:

  <%= fb_login_and_redirect root_url %>

In an IFrame application, this will redirect the IFrame to our site. When this happens, Safari and Chrome will block cookies. Instead, we want to redirect not just the IFrame, but the whole page. We’ll use a new helper for that (Facbooker2 only right now)

<% fb_login do %>
  window.top.location = 'http://localhost:3000/'
<% end %>

This gets us to our site without being in an IFrame. As the facebook connect process loads, we’ll get the cookies set. If we were to then redirect back to the IFrame version of our page, we would have session information. While this is functional, it’s an odd user experience to have a page outside of facebook. Let’s clean that up a little. I’m going to create an action to handle getting the session information. We don’t need to do anything in the controller. When a webkit user visits this page, Facebook will be able to set the login cookie. This will call the @auth.login@ event to be fired. We can hook into that to send the user back to the IFrame page. Our view looks like:

<% fb_connect_async_js2 do %>
FB.Event.subscribe('auth.login', function(response) {
        window.location.href = "http://apps.facebook.com/canvas_url/";
      });
<% end %>

We could add a spinner or some other message to make it look a little nicer, but that’s functional. Now, when a webkit user logs in they will be sent to our login specific page where the cookie will be set. Afterwards, they will be redirected back to the canvas url.

There’s still one problem. If a user somehow makes it to our login page while already logged in, they will be stuck there forever. We can add just a little bit of our logic to our controller to handle that.

  def create
    redirect_to "http://apps.facebook.com/canvas_url/" if current_facebook_user
  end

Now, if the user is already logged in, we’ll just redirect them back immediately. If they aren’t, we’ll wait for the login callback and will redirect them in the view.

That eliminates one of the major problems plaguing Facebook IFrame applications. Shortly, I’ll talk about how to make session handling work for logged in users so that you can use the built in Rails flash and session objects.