Repository navigation
Description
The toolbar works on posthog.com because it's sharing a cookie with app.posthog.com thanks to the shared "posthog.com" part. It doesn't work on kea.js.org. Same locally: it works between localhost:8000 (posthog app) and localhost:3000 (local docusaurus), but not with any other domain that points to 127.0.0.1.
Everything works fine if you click actions -> new action -> inspect element, as then we share the token directly in the URL.
I'm not 100% sure what's the reason, but I do have a hunch. Debugging the requests, request.user.is_authenticated already returns false when I open local.kea.js.org:3000. It seems that django either doesn't have access to the posthog session cookie... or has something that voids it.
I haven't tested it, but I think for this to work, we should set SameSite attribute to None on the app.posthog.com session cookie.
However, I'm afraid setting this for the full session cookie can expose us to various cookiesnatchers? (I visit your site --> you get my entire posthog session cookie in the response of the request made to /decide... and then who knows what you'll do with it).
I think a better approach would be to only share a random encrypted token in a SameSite=None cookie, which will only be used by the /decide endpoint.
However.... support for setting a random cookie with SameSite=None is only merged in to Django 3.1 (beta):
django/django@b33bfc3
... so I'll need to set it manually in some middleware. It should work though.
@timgl Is this an approach that makes sense and should I follow it further? Any alternative ideas on how to get this to work?
However, in case we can't get this to work reliably, we should "promote" the "inpsect element" button on app... perhaps putting it in the sidebar as a "go to site" link?
Activity
mariusandra commentedon Jun 26, 2020
Update, to test if this would work at al, I'm now setting SameSite=None for the django session cookie:

However I still don't see cookies sent to the

/decideendpoint when onlocal.kea.js.org:3000:Compared to

localhost:3000:Still not sure what are the next steps. CORS seems to be set up properly, though... 🤷
mariusandra commentedon Jun 26, 2020
Ah,
SameSiteonly works withSecurecookies... so it's time to set up local SSL and to try again.Unfortunately I was not able to get this to work either. I set the "Secure" and "SameSite=None" keys on the django session cookie:
... yet the cookie is not included in the request to
/decide.However, when I manuall create another cookie and set it to
SameSite=NonewithSecure=True... and access it on two sites, both served over HTTPS, I get something:It's still blocked "due to user preferences" when running in incognito, but the cookie is there in all other cases. So I think we have something I can work with.
To be continued.
timgl commentedon Jun 26, 2020
Here's a handy guide I wrote to setting up SSL locally.
Great work debugging this!
mariusandra commentedon Jun 26, 2020
Thanks... and yeah, I even added "step 0" to the guide :). (Sorry, I accidentally pushed it straight to master)
In any case, after trying a lot of different options, it seems that PR #1103 should make it work. It works locally with https urls and without... and it'll probably work in production as well.
The only danger is that I'm now setting SameSite=None on the django "sessionid" cookie. The fear I had above about someone sealing the cookie with JS is unfounded, as with "httponly" set to true (set by default), the session cookie is not reflected back in the response... and thus not readable by some JS XSS hack. (Only django sees it)
With CORS being off on most requests as well (except for /decide and some others), I think there's not much that can be exploited. However I'm always paranoid about security, so I'd appreciate a second and third opinion on this.
timgl commentedon Jun 26, 2020
I believe your conclusions are correct and happy with current implementation. The only other thing we could look at is having a separate cookie for the 1st party and 3rd party (see this page, "If you have cookies that you access in both a first and third-party context, you might consider using separate cookies to get the security benefits of SameSite=Lax in the first-party context.").
The "might consider" indicates to me that it's more an ultimate fallback, and as you said all of our endpoints that are crucial have the correct CORS headers set.
mariusandra commentedon Jun 26, 2020
I think we're good as well. We just need to continue to keep a tight lid on all CORS endpoints in the future.
I did propose to implement a "cookie that's only used for /decide" some comments prior, yet I'm not sure it makes sense anymore or right now. If we implement changes to this system, it might be worth doing them in a broader context, when we implement a decent "you are logged in from X" user session system as well.
We'll need to do this some time soon anyway, as the current temporaryToken system can only be used from one device at a time.
@fuziontech @EDsCODE any thoughts on this? Do you think it's safe to add SameSite=None to the django session cookie? Together with "httponly", so it's not readable by any JS script parsing the response.
mariusandra commentedon Jun 30, 2020
PR #1103 merged, now this should just be tested on app.
mariusandra commentedon Jun 30, 2020
It works with Chrome & Firefox. Some issue still with Safari.
mariusandra commentedon Aug 3, 2020
I did another round of tests.
Assuming your site is properly listed in the list of accepted URLs under /setup, this is what happens:
Firefox = everything works. I logged in to app.posthog.com, opened kea.js.org and the button was there! I could authenticate, etc.
Edge = the same. Everything worked as it should by default.
Safari = I had to remove the first checkbox here for the toolbar to open automatically. Clicking "Launch Toolbar" worked though.

Chrome = worked by default, except in incognito mode where I had to update this cookie setting:

Thus the bug reported by this issue is resolved.
jramiresbrito commentedon Aug 4, 2022
Hey guys, I can't launch the Toolbar here. What's the value to put in the CORS header?