The Facebook platform offers a great deal of functionality, and I have been using it recently for user authentication and management for a web application. Last December, Facebook implemented their mandatory migration to OAuth 2.0, causing breaking changes for those of us naïve enough not to monitor their blog. As part of this migration, they changed both their cookie format and policy, which will make life more difficult for server-side developers.
The new cookie format is a little different. Besides a different naming convention (fbsr_appId), it no longer contains the raw access token. It consists of 2 parts, a signature and a payload, separated by a period and base64 URL encoded. The payload can be verified by doing a SHA-256 hash on the payload, using the application secret as a key, and comparing that hash to the signature. The payload itself is JSON containing a "code" property. You submit this "code" (the authorization grant, in OAuth-speak) and Facebook application ID and secret (the client credentials) to Facebook to get the OAuth access token. From this point on, the server can use the access token to access whatever protected resources (such as the user profile) that the Facebook user has granted the server.
This new cookie format seems an improvement in terms of security. Since the access token is no longer stored in the cookie, you don't have to worry about it being exposed over the network. The code can only be used with your application secret, which is never sent to the browser. Unfortunately, Facebook not only neglected to document this new cookie, but they are discouraging other developers from using this cookie. This is supposed to be an implementation detail, which Facebook can change at any time. So for those of us not using their PHP SDK, how are we supposed to proceed?
On the blog, Douglas Purdy of Facebook outlined the following options (in his words):
- Make the call on the client side using the FB.api method the JS SDK.
- Get the access token from the JS SDK and pass it to the server yourself (FB.getAccessToken). Make sure you are doing that over a secure link.
- Just do the auth on the server, rather than using the JS SDK. It is hyper-simple.
Unfortunately, none of these options are acceptable. A server cannot trust anything that comes from the client (nix options 1 and 2). Option 2 now requires a secure link where we previously did not. And doing the "auth" on the server does nothing for the client.
It seems the cookie solution is ideal for seamless browser/server Facebook access. Obviously, Facebook thinks so, as they are using this method for their own PHP SDK. Unfortunately, they don't seem to want others to use the same method: "do as I say, not as I do". I'm not really sure what approach I should take at this point. On one hand, I don't want to use an unsupported method. On the other, the cookie method is so much easier, and Facebook can't really introduce a breaking cookie change without also breaking their own PHP SDK. Figuring the cookie format by reading the PHP SDK code is not hard. In fact, the facebook-graph-plugin for Grails already implements this cookie handling.
What approach would you take?