Search code examples
expresscookiessession-cookiesexpress-session

Cookies (set-cookie header) lost after ~90 seconds of idle when post request is from external source. Express + express-session example


I have experienced very strange behavior of set-cookie header in request.

Tried to deal with some api 3ds calls in payments online system, when need to redirect user in another tab/window and then return in site.

And sometimes user was logged out.

Payment api send request to some /3ds route with POST method. When i debugged this route, i saw, that cookie property in request header is lost (not in all situation, but in 1 of 10).

I tried everything and it didn't work. So i create very simple Express app and one route /test.

const app = express();

app.use(expressSession({
    secret: 'secret',
    cookie: {
        maxAge: 30 * 24 * 60 * 60 * 1000,
        httpOnly: true,
    },
    resave: true,
    saveUninitialized: true
}));

app.use('/test', (req, res) => {
    console.log(req.headers);
    res.status(200).send();
})

And file with submit form

<html>
    
    <body>
        <form  target="_blank" name="downloadForm" action="http://localhost:3000/test" method="POST"></form>
    </body>
    <script type="text/javascript">
                const seconds = 90;
        window.onload = setTimeout(() => {
            submitForm();
        }, seconds * 1000);
        let i = 0;
        setInterval(() => {
            console.log(i++)
        }, 1000);
        function submitForm() { downloadForm.submit(); }
    </script>

</html>

When seconds less then 91, then cookies present in req.headers, and when more, cookies undefined.

When using GET everything works.

What cause of it?


Solution

  • Cookies without SameSite attribute are treated almost as if they had SameSite=Lax. In a strict interpretation this value means that a cookie is included in a cross-site navigation GET request, but not in a cross-site navigation POST request.

    But such a strict interpretation would prevent a SAML logon flow that uses RelayState cookies, and break existing websites. For this reason, browser vendors have implemented a "Lax+POST intervention", which allows cookies without SameSite attribute in such POST requests for a short time span (approximately two minutes). See also Why is cookie without SameSite attribute sent on cross-domain form post?. In this regard SameSite=Lax differs from no SameSite at all.

    If you want cookies in cross-site POST navigation to be available for longer time spans, you must set the attributes SameSite=None; Secure and serve the cookies over an HTTPS connection.