Cross Site Cookies
Cookies aren’t allowed between hosts, unless they’re related. Unfortunately, that comes with a pile of caveats, some of which make local development hard.
Cookie Security
Ok, so HTTP has cookies, since before most of us touched a web browser. One of the features of cookies is that you can set the domain tree they apply to.
BUT.
- You can only set a single root domain, but it does apply to all subdomains
- That scope must include the current site (ie, you can’t set a cookie on some random other site)
- It cannot be a public prefix (eg, you can’t set a cookie on
comorioand have it apply to half the internet)
My Task
As a background: I run Teahouse Hosting (you should pay me to host your site).
I want to implement a signup button on the main site. (Which is static.) And I would like that button to change based on the user’s current auth status in the admin panel. (Which is a separate page. Because the main site is static. So I have to use javascript. Because static.)
I did try this with fetch() and CORS, but it turns out if you want to make cross-site requests with cookies, you have to opt-in on both sides and open a train-sized hole in your security.
So I’m using cross-site cookies instead.
Doing this on real domains would be fairly easy, but I don’t want to develop in production, and not every dev box has a public domain routed to it. And I want to stay in the secure context carveout for localhost.
The development environment, btw, is two local servers:
- A static site auto-builder & server for the main site
- An ASGI server for the admin panel
The Problems
So it turns out btowsers have complicated rules about if two domains are related. And I encounted some other security features that hindered me.
-
localhost:42andlocalhost:69are completely different, unrelated sites -
localhostcounts as a public prefix, so only sites onlocalhostcan set cookies onlocalhost - Firefox will ignore
/etc/hostsforlocalhostand all its subdomains, instead resolving everything to127.0.0.1
And of course, none of this is documented (or, it’s burried in other documents I was too tired to search for).
So what did I try to discover these rules?
- Just run them on
localhost:8000andlocalhost:8080 - Run them on
127.0.1.1:8000and127.0.2.1:8000and use/etc/hoststo give them names - Use the solution below and use the names
alpha.localhostandbravo.localhost
None of that works.
The Solution
Ok, so I apparently need to have my applications accessible on teahouse.localhost and something.teahouse.localhost for it to be a representative (and working) test of the cookie situation.
The Application
The admin panel sets some non-tracking status cookies on login with their domains set to the apex (teahouse.localhost or teahouse.cafe, depending on the environment).
The Routing
I installed Caddy on my system and used this config:
http://localhost, http://*.localhost {
bind 127.0.0.1
reverse_proxy :8000
}
http://alpha.localhost, http://alpha.*.localhost {
bind 127.0.0.1
reverse_proxy :8001
}
http://bravo.localhost, http://bravo.*.localhost {
bind 127.0.0.1
reverse_proxy :8002
}
http://charlie.localhost, http://charlie.*.localhost {
bind 127.0.0.1
reverse_proxy :8003
}
http://delta.localhost, http://delta.*.localhost {
bind 127.0.0.1
reverse_proxy :8004
}
http://echo.localhost, http://echo.*.localhost {
bind 127.0.0.1
reverse_proxy :8005
}
So now port 80 will be proxied to a bunch of stuff I can run locally, and I can use the domains for a lot of things. In this case, I’ll put the site on teahouse.localhost and alpha.teahouse.localhost (run the servers on ports 8000 and 8001.)
The Result
After this wild goose chase and a more than a few minutes banging my head on my desk, this works beautifully. I’m able to easily develop the bit of JavaScript I need. I’m able to log in over here and see the button change over there. It’s great.
I just need a nap.