« Smerity.com

Fast Facebook OAuth Login

The Facebook OAuth login is used everywhere on the web but is slow. In order to complete the server-side authentication, many round trips are required before you can confirm the person's identity.

The Issue

The diagram below describes the round trips involved in performing an OAuth login via Facebook. Notice there's a lot of them... The user needs to endure at minimum three round trips, bouncing between your site and Facebook itself. Your server also needs to do two round trips to Facebook on top of that before confirming the user's identity.

These round trips take a good chunk of time. There's also the risk that the call to the Facebook API will never return or experience lag (maybe even tripping a timeout) -- not uncommon in my experience. Sadly, there's not too much of this process that can be optimised away other than the call to /me. It'd be optimal if at least we could skip the /me call.

In a perfect world, Facebook would send back {user_id, access_token, expires} -- but this isn't a perfect world, we only get the latter two =[

Optimal Theoretical Solution: Caching

Use just the {access token, expires} tuple to identify the user (without access to their Facebook ID or /me)

  • Facebook's reply to OAuth is only the access token and the expire time
  • Assume the access token is still valid and linked to the user (do not like)

The word assume in that sentence scares the hell out of me as I hope it does for you. I don't like to assume identities when the user is logging in to my application. Whilst valid access tokens for an application need to be unique (as otherwise Facebook couldn't perform look-ups using them), nowhere does Facebook explicitly say that they won't re-use old invalid tokens for different users.

If an old invalid token T from user A is later re-used for user B, your application could log user A in as user B

What about using the expires time that comes along with the access token (see Access Token Debugger for more details). One could use both values, {access token, expires}, to uniquely identify the given access token. If a new access token has been issued to a different user of your application, they should have different exires. Thought it sounds reasonable I wouldn't necessarily trust that method without feedback from Facebook developers -- a mistake is far too costly in a step as important as the authentication process.

Sub-optimal Practical Solution: Smooth the Flow

If you can't get speed, go for interactivity -- one long unresponsive load becomes two responsive ones

To make the login process flow better, one could break the /oauth/authorize and /me Facebook API requests into two pages:

  • Page 1: /oauth/authorizeLoading user details...
  • Redirect to Page 2 either (a) after a predefined timeout limit or (b) when the server informs the user that the /me request is complete
  • Page 2: Normal application

The optimal way of completing the redirect is via real-time Javascript push notifications (such as Socket.io). This way the user can be alerted immediately when the Facebook API request has returned. The less optimal method is a stock standard redirect after a predefined amount of time, looping until your application has completed the API request.