Thursday, January 12, 2012

Dealing with zombie Facebook cookies...

Not able to logout in your Facebook Connect applications? Facebook recently pushed a change in the past day or so such that the domain= parameter is now added to your fbsr_ cookies. If you find that your cookies are not being removed after a user attemps to logout, chances are you're experiencing the repercussions of these recent changes.

In the timestamped version (1326413659,169943147), there is a section that was added to the Facebook Connect Library:

23402348 }
23412349 return b;
23422350 },
2351 loadMeta: function() {
2352 var a = document.cookie.match('\\bfbm_' + FB._apiKey + '="([^;]*)\\b'),
2353 b;
2354 if (a) {
2355 b = FB.QS.decode(a[1]);
2356 if (!FB.Cookie._domain) FB.Cookie._domain = b.base_domain;
2357 }
2358 return b;
2359 },
23432360 loadSignedRequest: function() {
23442361 var a = document.cookie.match('\\bfbsr_' + FB._apiKey + '=([^;]*)\\b');
23452362 if (!a) return null;

The regexp apparently fails to match because there is an extra quotation mark. Instead of:
var a = document.cookie.match('\\bfbm_' + FB._apiKey + '="([^;]*)\\b'), b;
It should be:
var a = document.cookie.match('\\bfbm_' + FB._apiKey + '=([^;]*)\\b'), b;
If you inspect document.cookie in a JavaScript console, you'll see no sign of how this regexp could match (i.e. the regexp would match fbm_1234="abcde" but not fm_1234=abcde). You can also use the Chrome/Safari Web Inspector, put breakpoints on this function, and use the deminifier feature (look for the {} icon at the bottom) to double-check.

Background info: Before the OAuth2 migration, the fbs_ cookie was used. Included in the fbs_cookie was a query string that needed to be decoded and the base_domain parameter used for the domain= cookie parameter.(For more background about how to set or delete cookies in JavaScript, see: http://www.quirksmode.org/js/cookies.html.)

Cookies be cleared by setting the expiration date to 01/01/1970 GMT. However, most browsers won't know how to delete the cookie unless the path= and domain= parameters are set correctly too. In other words, if you had a cookie named fbsr_1234, with domain=abc.com, the browser would not be able to delete it unless you also specified this parameter.

Until now, OAuth2 didn't include the domain= parameter in fbsr_ cookies. But with today's recent push, it is now being used. The result? If you had an old cookie without this domain= parameter and attempted to logout with this new JavaScript code, you might find that you're unable to clear them. You may also encounter strange logout issues in general and not see the fbsr_ cookie cleared correctly.

When you logout, a cross-domain request gets sent to Facebook to invalidate the session. When you hit reload and invoke another FB.init() command, another request gets sent to Facebook's site -- since FB recognizes the existing cookie as invalid, it correctly deletes the cookie from your browser (the cross-domain response appears to pass in the domain= parameter correctly). Unfortunately the clearing of the cookie initially doesn't work because the fbm_ cookie isn't parsed correctly because of this regexp bug.

Facebook will most likely fix this issue soon, though in the interim your users may not be able to logout of your app. One thing we've done is to use a server-side code to instruct the browser to clear the cookie, though it may not always work unless your page invokes FB.init() properly and receives back a cross-domain request from Facebook to set the domain= properly.

You can examine this code for how you can delete cookies from the server-side:

https://github.com/rogerhu/facebook_oauth2/blob/master/views.py

Want to track Facebook Connect JavaScript changes? Check out:

No comments:

Post a Comment