Friday, October 18, 2013

How does Facebook set cross-domain cookies for iFrames on canvas pages?

I was browsing Facebook's documentation reading about canvas applications and I came across an example application: http://developers.facebook.com/docs/samples/canvas. As I read through their example, however, I got very confused about their use of cookies in the iframe application.

A little backstory...

I had already played around with using iframes for embeddable widgets (unrelated to Facebook) and I found out a few browsers (Chrome, Safari, etc.) have strict cookie policies and don't allow cross-domain cookies set in iframes (Firefox, on the other hand, allows iframes to set cross-domain cookies in iframes). For example, if foo.com has an iframe with src="http://bar.com/widget" the iframe widget will not be able to set any cookies for bar.com and therefore will have trouble persisting state within the iframe: bar.com will interpret every request (including ajax requests) from the widget as a fresh request without an established session. I struggled, and found a way around this by using JSONP and javascript to set cookies for foo.com instead...

... and so?

Well, I was looking at the example canvas iframe Facebook application and I noticed that their application (hosted on runwithfriends.appspot.com) is able to set a cookie, u, with the current user's id along with a few other parameters for the runwithfriends.appspot.com domain. It sends this cookie with every request... and it works in both Chrome and Firefox! WTF? How does Facebook get around the cross-domain cookie restrictions on Chrome?

(I already know the answer now, but I thought this might be helpful for anyone struggling to figure out the same thing)

So the iFrame isn't actually setting the u cookie for the runwithfriends.appspot.com domain. What Facebook does is it creates a form, and uses javascript to submit the form on page load. Since the form's target is the iframe, it doesn't reload the page... it just loads the iframe with the POST's response. Apparently even Chrome and other browsers with strict cookie policies set cookies for cross domain requests if they are POST requests...


As you can see the answer is simple, and could be implemented by just creating a handler (could be a Servlet or anything that can catch some parameterts and transform them into cookies), like this: