Search code examples
node.jsexpresscookiesgithub-pagesfly

Express cookie getting sent for Firefox but not Chrome


I've got a Node backend deployed on Fly.io and a Vite React frontend on GH Pages. There is a login that uses Express, which I am finding works 100% as intended with Firefox, but not on Chrome (or Edge, for what it's worth). The login request does get a 200 OK response, but the cookie (which appears to be called connect.sid) does not get sent.

Luckily, Chrome Dev Tools is smart enough to be able to identify this issue: it tells me that because my frontend and backend are on different domains, I need to set the cookie's sameSite attribute to "none". I do so, but it still won't work, and Dev Tools identifies another problem: you can't have sameSite = "none" without also having "secure" set to true. So I do that too, and it still won't work. Only now, Firefox doesn't work either -- the set-cookie attribute in the response header is gone. Dev Tools no longer has any tips for me on what's going wrong, so I googled it. One thing they recommend is telling Express to "trust proxy", so now I've got it set up like

app.set("trust proxy, 1");
app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: { sameSite: "none", secure: true },
  })
);

which doesn't seem to change anything. The other thing I've read is that in order for the secure attribute to work, the front and back both need to be using HTTPS. I suspect this is the problem but I don't see why: the URL for both (frontend on GH Pages, backend on Fly) do both have https://. But when I have my backend log req.protocol when I try to login, I do get "http" instead of "https". Does anyone have any thoughts?


Solution

  • I couldn't tell you why this worked, but based on this person's experience I tried switching from the "express-session" library to the "cookie-session" library, and it worked on Chrome just fine. Go figure. The cookie-session syntax is a little different, so now I've got it written like

    app.use( cookieSession({ name: "session", keys: ["key1", "key2"], maxAge: 24 * 60 * 60 * 1000, sameSite: "none", secure: true, }) );

    Using Passport with cookie-session also requires an extra little work-around that I've outlined here.

    If anyone is interested in telling me why cookie-session has an easier time accepting cross-origin cookies as secure, I'd be interested in hearing the reason! Leave a comment!