Third party cookies with IE at 2am


Let me tell you a modern web developer horror story.

You’ve been working on a feature for months. This feature is a collaboration effort of two companies, integrating via API and some iFramed content. You’ve tested most possible scenarios. Both sides have QA teams running these scenarios again and again before launch. Everything seems fine and you’re happy! Then someone from the other team mentions something in the unified slack channel; “I can’t seem to login with Internet Explorer”.

Now, as an experienced developer, you know that this isn’t possible. You’ve tested this site on IE9, IE10 and IE11! This can’t be right… they must be mistaken. My feature is flawless, you say. Well, if you’re using iFrames and embedding your site in another site’s domain, this is not only possible, but it will happen!

If you arrived here looking for a solution for cookies not being saved inside an iFrame, feel free to skip to the end.

Some background

The feature in question is, allowing businesses from FreshBooks to register and clear their invoices straight from their FreshBooks dashboard. If you’re interested in how this looks, head to the FreshBooks blog. In order to make this functionality, we decided to build a Hybrid API. One part is the backend API, to let FreshBooks query our system and check if the user in question is already registered with Fundbox. The other part is an iFrame front-end API, to let FreshBooks show a modal inside their dashboard which depends on the backend APIs results, to either show a new user sign up page, or a log-in page for an existing Fundbox user. I won’t go into details, but this integration made us do some thinking, and we’ve come up with some creative solutions which deserve a blog post for themselves. But I’m here to tell you a horror story, remember?

Launches are fun when they go smoothly

Launching a feature which involves two development teams from different continents and time zones is tricky. When we finally got everyone at their workplace and started working towards the launch, everything seemed to go fine. Some small bugs crept up, like they always do. Some we fixed on the spot, while for others we decided that they’re not show-stoppers and moved them to after launch. Then, the dreaded words were heard in the slack channel. Something doesn’t work in Internet Explorer…

“I can’t seem to login with Internet Explorer”

This can’t be right, right? We’ve tested with IE, albeit not in production, but we have several staging environments and we’ve tested, and well, it works. Ok, so we test again. I fire up the lovely SauceLabs interface, choose a windows machine with IE 11, and try to login via the iFrame. It works! HA! see guys? I told you it works, something is wrong with your machines…

The QA guys from across the ocean check again on a native IE installation, still no dice. Can’t seem to login, OR register! We check again, this time in a virtual machine, and it indeed doesn’t work. We bring a PC with a native IE – doesn’t work as well. 0_o, it’s 9PM and it’s launch day. This can’t be good…

Debugging iFrames is a fun time that everyone enjoys.

Baffled by the fact that some IE installations work and some don’t, we tried a BUNCH of different scenarios. Antivirus, malware, different networks, WiFi settings. Nothing seems to be the culprit.

Then something pushes me to check out the security settings of the misbehaving IE installation. I lowered all of them to their lowest settings, and everything is peachy, no bug. hmmmmmm

After understanding exactly why the login/register forms didn’t work, we arrived at the fact that the AJAX requests weren’t even leaving the browser. With some additional digging into the code, we placed the the blame on a small piece of code which makes sure that cookies can be saved before even sending the AJAX request. Then we tried to login with this exact URL, but this time in a tab, not an iFrame on another domain and… BOOM. Everything is silky smooth!

The question now is, why then can’t we save cookies inside the iFrame on another domain?

Then the slack channel rings with some more info about this bug…

Safari has the same bug…

How? Safari is a modern browser, unlike IE, right? I mean, usually I don’t even bother checking it, as it’s very modern and cool, and stuff just works there. Also, it has barely any usage percentage. But ok, Safari shows the same behavior, so I can debug this issue natively and much more quickly on my Mac. If the symptoms are the same, it must be the same bug, hence the same solution, right? WRONG! But we’ll get to that.

What the hell is p3p?

After some googling, we arrive at some blog posts that describe the same symptoms, and offer a solution. Let me walk you through it.

There’s a w3c standard called P3P, from 2002, that proposes a way for sites to describe how they store and contain your data over cookies. This standard is not a standard per se, as no browsers have implemented it, mozilla even had this at some point and removed it. No browsers, except of course, INTERNET GORRAM EXPLORER. Now, ok, this sounds not half bad, I mean, if a site is honest about it’s data storing over cookies, and your security settings don’t allow for this, your browser must do the responsible thing and let you know it blocked the cookies, only of course Internet Explorer has a half-assed implementation of this, meaning they will only block the cookies. Without letting you know. Just fail quietly. Jee, thanx!

The solution seemed easy enough

After some digging into the standard, and some helpful Stack Overflow posts, we arrive at a proposed solution. All we have to do, is add an xml file, to a path called “known location” which will describe to the browser, our sites cookie usage policies. A word of caution though, these policies are coded in a VERY weird and unreadable way, something like this

And the xml file should be served from a static location, /w3c/p3p.xml and should looks something like this:

If that’s not enough (this didn’t solve the problem btw), you have to add a header, to all requests on your site, that’s called “compact policy” that will have the same policies statements, and will link to said xml. Because having it in the same url on all sites (what’s called a known location) isn’t enough. The header should look something like this:

Ok, we got the solution, we added a header, with the policies we just found on Stack Overflow. Now what? Now comes the part where we realize, that all those policies are legally binding, and if you put the wrong ones, somebody might sue you, as they have real world meaning. OMG! So how do we find out the right ones? Well, there’s some apps you can download, most of them are antiques and costs money, that will let you edit them. One free one we found is IBMs p3p editor.

Luckily, there’s another solution

Ok, did I mention that IE half assed this implementation already? I have! And I will again. Turns out, that dear IE doesn’t really care what you put in that header, as long as it’s there. Google and Facebook have this header and the contents of it just states that they don’t support it. Because it’s an unfinished standard. And is outdated. And is stupid! So our solution now looks like this:

Yes, we declare our p3p policies as a potato, and explorer then let’s us save the third party cookies. geeez. This solution, also isn’t technically “Fraudulent” but simply is invalid. More on that here

Unfortunately, that wasn’t all of it

When we tested this scenario, we discovered that it didn’t work. Because we assumed that having the same bug, means the same solution for both IE and Safari. It doesn’t. Safari doesn’t care about stupid outdated unsupported standards. What safari does care about, is whether you have visited that site before. If you have, they will allow it to set cookies in an iFrame, if you haven’t, well then, bad luck.

This realization came to us after spending about 2 hours, now VERY late at night, trying to test p3p headers in Safari…. And only after both teams sat down to talk the solutions over on Skype, and the FreshBooks team told us that they research came up with the fact that Safari dropped the p3p support somewhere in version 5.1, sigh.

A solution for Safari

What quickly became understood, that Safari will allow cookies, if the user has previously visited the site not in an iFrame, and that site has placed cookies. Which is good right? I mean, Fundbox users have at least been once on our main domain, This is BTW why we didn’t find this bug right away. We all had previously visited on all our browsers. Alas, the new users, those who will use the feature, will have never been to, as the whole point of this integration, is to let them use Fundbox straight from the FreshBooks interface.

So finally, at 2am, we arrive at the solution.

Check to see if we can set cookies. If we can’t, we then show the users a friendly message, not unlike many you’ve seen on many European site. requires cookies. Please click here to continue

After the user clicks the accept button, we then open a small popup, on the right bottom side of the screen, which will load a page on, which the whole purpose of setting a small cookie, and then message back to the iFrame that cookie has been places. The iFrame will then close the popup, reload itself, and the user can continue with his flow.

This happens very quickly, and because the button is animated with a loading state, the popup opens and closes without the user even noticing this little technique.

Solution overview

In the iFrame we have the code to detect if a cookie can be set, and if not, we remove the “hidden” class of the #cookieless div overlay, which contains the message and the button.

When the user clicks the approve button, we launch a small popup, and set a cookie in that popup

The mouse down part is a small optimization, as safari takes a second or two to check whether the popup window was originated by a user action, or by malicious code. We then add a loading state to the button, and open the smallest popup window, in the right most bottom most section of the screen.

The popup page loads with this small bit of code in the head:

Which sets a cookie, tells the opener (the iFrame) to reload, which works because they are on the same domain, and then closes itself.

Lessons learned

I’ve been doing web development for almost 10 years, and as it turns out, IE doesn’t seem to stop surprising me.

Another thing that I will always remember, is that bugs will happen on production, even though you have tested thoroughly before getting the code to production.

But the horror story does have a happy ending, as we successfully launched this feature to a small subset of our users the very next day, and they love it.

A great amount of respect goes to members of both teams on collaboration and quick response in fixing these very hard to trace bugs!

Fundbox helps small businesses to fix their cash flow by turning unpaid invoices into money in the bank. Apply now to start clearing your unpaid invoices.

  • sergeylukin

    Very informational post. Thank you!

    I’ve never heard about this Safari 3rd party cookie policy before. I can imagine how hard it was to track this behavior down. Well done people.

    I had to get my hands dirty with it just to see it in action and indeed verified that Safari doesn’t allow writing cookies on 3rd party domain (in an iFrame) if that 3rd party domain yet didn’t successfully set at least one cookie via Set-Cookie response header.

    Anyone interested in live demos can find them below.

    This example will not set a cookie in Safari even if you visit (because doesn’t send cookies via headers):

    while this example will set a cookie only after you visit at least once (because sends a cookie via Set-Cookie response header):

    mind-blowing stuff…

  • sergeylukin

    Here is a live demo including P3P header and Safari popup trick explained in this post:

    • Alex Ponomarev

      Sergey, thanks a lot for working demo! Saved a lot of time for me

      • sergeylukin

        Great! I did it to use myself as a reference as this is kind of stuff that’s easy to forget. Glad it was helpful for you too.

  • csmoak

    The solution for Safari doesnt seem to work with Chrome. Do you have the same issue?

    • Alex Volkov

      I’m pretty sure chrome allows for third party cookies without a problem.
      Are you getting an error?

      • csmoak

        I’m not sure what the default value is in chrome but it does allow you to turn on blocking of third party cookies. Almost 25% of my test users for a product I’m launching had it on and we’re experiencing issues.

        I tried the example below in chrome and the pop up opens but the success notice that cookies have been set never shows

  • Bairfhionn Isu

    I had a loud laugh reading this article.

    We had the EXACT same problems, exact same way of discovery… It felt like past me wrote it.

    Thanks for this writeup. It’s the clients decision if he wants to actively circumvent a (shitty) security system of Safari or not, but it’s a weird solution for a even weirder problem.

    Thank the gods we didn’t have to worry about mobile on this one…

  • Bethany Meyer

    Thanks for posting this! I found surprisingly few posts about this issue in my searches.

    I’ve been feeling like Safari is the new IE lately. Is it just me?

  • mobileless

    > the popup opens and closes without the user even noticing this little technique.

    This is true on desktop. Unfortunately on most mobile browsers, the popup opens full screen and is potentially quite ugly and confusing.

    • Alex Volkov

      Pretty sure that only desktop has this restriction, I haven’t seen this behavior on mobile safari as of yet

      • mobileless

        The people I work with have told me they have seen it with mobile safari, but I haven’t verified that myself yet.

        What I have verified myself is that mobile Safari will ignore cookies on cross-domain requests, even if the correct CORS headers are used. It is possible for users to configure it not to do this. But for many people the default settings are to block cookies in this case. The cookie work-around described here is a possible solution to that problem.