Munchkin on AWS Elastic Beanstalk is a little tricky

More fun with Munchkin domainLevel tonight. A client hired an outside design firm to work on some LPs, and the designers couldn't figure out why embedded Forms 2.0 forms weren't relaying the Munchkin cookie, even though anonymous Visit Web Page activity was being logged (though there was a new anonymous lead on every page load, a valuable clue).

The firm was hosting the pages on http://clientname.elasticbeanstalk.com for QA. I'd recommended a subdomain of the client's domain instead — otherwise, associated leads would be lost upon navigating to the Thank You URLs on the client's main site, strongly limiting real-world tests. Indeed, hosting on http://pages.clientname.com would've sidestepped the problem. But that would've deprived us of a nice teachable moment, so it's just as well!

It was quickly clear that the cookie wasn't being passed because it wasn't saved in the browser's cookie store to begin with. A quick test:

> document.cookie="_mkto_trk=id:AAA-BBB-CCC&token:_mch-elasticbeanstalk.com-12344; expires=Wed, 18 Apr 2018 02:37:14 GMT; path=/; domain=.elasticbeanstalk.com"
< _mkto_trk=id:AAA-BBB-CCC&token:_mch-elasticbeanstalk.com-12345; expires=Wed, 18 Apr 2018 02:37:14 GMT; path=/; domain=.elasticbeanstalk.com"
> document.cookie
< ""

The cookie is discarded, even with a well-formed call to the document.cookie setter.

I then remembered that, during my research into Munchkin's domainLevel parameter (for a long blog post that's still in Draft mode, sadly), I'd seen some Amazon-supplied entries in the Public Suffix List.

For those who don't know, the PSL is the list of domains called "public," though a more accurate term would be "no longer available for private registration or use". These are domains whose subdomains may be used by private entities in the future, but the domain itself is considered public (though it may be currently registered by a private entity, which is confusing, as we shall see).

The PSL contains mostly obvious entries: old TLDs like .com and .net, new gTLDs like .space and .solutions, and country-specific ccTLDs like .au. We all know you can buy mystartup.net from Dotster, but you can't buy .net itself, and you can't buy Australia's whole TLD!

And the PSL includes second-level domains (SLDs) classified as public, like .com.au. You can register a commercial entity mycompany.com.au, but you can't have all of com.au to yourself, it should be clear.

There are some quirky reserved SLDs under the new gTLDs, too: you can't register ballooning.aero but you could register sanford.ballooning.aero, for what it's worth!

At first glance, it may seem strange that the PSL is loaded into browsers at all (and all modern browsers do keep an updated copy). What does the browser care if someone controls the whole of ballooning.aero or just countyfairs.ballooning.aero, as long as it can get to http://broome.countyfairs.ballooning.aero?

The answer is: it doesn't really care until you try to set a cookie. Because security.

Here's the rule: you can only set cookies on private domains. This is because the (quite easygoing) security policy for cookies allows you to set a cookie at one of your parent domains. That cookie is shared across all other subdomains of the parent. It's this policy that allows a cookie set by your Marketo-hosted pages.example.com to be read by your corporate www.example.com and vice versa, keeping the lead associated. (You could even be at a deeper subdomain like ny.us.pages.example.com and store a cookie for use by all of example.com: that's why I said "one of your parent domains".)

If the PSL weren't used, the browser wouldn't be able to stop you from setting a cookie at the .com level, which would then be seen and used by all other .com sites. A security disaster in all directions. So not only having a PSL, but keeping it up-to-date, is essential (in fact, if you go back to old browsers that don't know about the latest gTLDs you can set cookies at domains that should be prohibited, like ballooning.aero, which is yet another good reason to keep browsers updated).

So, back to pages.example.com setting a cookie at the parent level example.com. That'll work splendidly if example.com is a private domain. And 99.999% (really, even more) of the domains that end in .com are private, so it's usually not a problem.

But Amazon didn't want elasticbeanstalk.com to be private. So they submitted elasticbeanstalk.com to the PSL.

The reason is pretty clear: EB is a heavily multi-tenant system and a tenant given the hostname client1234.elasticbeanstalk.com should not be able to inject cookies that would be read by client6789.elasticbeanstalk.com. It's a wonder that more multi-tenant services don't add themselves to the PSL, by the way. Kudos to Amazon for being proactive.

But Munchkin doesn't adjust for this automatically. When Munchkin sees a gTLD (3 letters or more, like .com), it assumes the subdomain is private, so it automatically sets the domainLevel to 2 (elasticbeanstalk.com). You need to set it to 3 instead:

Munchkin.init('AAA-BBB-CCC', { domainLevel:3 });

By the way, I have a little JS snippet that can automatically determine the shortest parent domain that will actually accept cookies. No guesswork, so no mistakes. I'll be publishing this snippet in that other related blog post. If you're interested, you can contact me to get it now.