April 30, 2013

Safari, 3rd party cookies, and Facebook apps

The default settings for the Safari web browser block 3rd party cookies. This means that web apps hosted on https://mysite.com will not be able to set cookies when displayed within an iframe in a Canvas App (https://apps.facebook.com/myappdomain) or Page Tab. Problems ensue when the web app relies on cookies for sessions and CSRF checks.

Here is an ugly but functional fix. When the page first loads within the frame, check if any cookies are set. For example, a Laravel-based site might use this PHP code in a before filter:

if (count($_COOKIE) === 0) {
     return '';
}

This will redirect the user out of Facebook and into a page on mysite.com where the web application can set cookies as the 1st party instead of the 3rd party. With Laravel, the session token and payload cookies are set automatically at this time. Then page writes out the following code in the HTTP response to redirect the user back into the Facebook app:

''

With a broadband connection and healthy web server, the redirect happens so fast on a speedy site that most people do not notice the URL changing to from a Facebook URL to an external URL and back. This time when the check for cookies returns a number > 0, the app continues as usual. In my experience, the app is able to make changes to the cookies now as well.

Caveats

This quick fix does not cover situations where the user is landing on a page deep in your app. If user visits https://apps.facebook.com/myappdomain/internalpage, they will be redirected back to https://apps.facebook.com/myappdomain after the cookie is set. This can be fixed by saving the full URL the user landed arrived at without cookies, and returning the user to that URL instead of https://apps.facebook.com/myappdomain.

This fix will also put users who have intentionally disabled cookies into an infinite loop of redirects between the Facebook app and /cookieredirect page. Whether or not this is an issue for your app’s audience is up to you. A way to prevent the loop may be to store the number of times the user has gone through the redirect, and send the user to a page that doesn’t redirect them again if they have gone through it more than once without the cookie being successfully set.

An Alternative

An alternative to the redirect is to briefly open a popup window containing your own site, and use a similar behaviour as the /cookiefix URL to set cookies, and then close the popup. Use an interaction like a click to open this popup, otherwise Safari may block it.

Related links:

Discussion on Stack Overflow

Another discussion on Stack Overflow