question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Undici strips out set-cookie headers, even when "credentials: 'include'" is set

See original GitHub issue

Bug Description

Undici strips out set-cookie headers, which is expected per the fetch API spec. What is not expected though is that the set-cookie headers are stripped out in the presence of { credentials: 'include' } in a fetch request. Here is the relevant portion of the fetch API spec: https://fetch.spec.whatwg.org/#example-cors-with-credentials

Reproducible By

server.js

const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.set({
    abc: '123',
    'set-cookie': 'hello=world',
  });
  res.send('Hello World!');
})

app.listen(3333, () => {
  console.log(`Example app listening on port ${port}`)
})

client.js

const { fetch } = require('undici');

async function get() {
  const headers = await fetch('http://localhost:3333/', { credentials: 'include' })
    .then(async res => {
      for await (const chunk of res.body) {}
      return res.headers
    });

  console.log(`abc: ${headers.get('abc')}`);
  console.log(`set-cookie: ${headers.get('set-cookie')}`);
}

get();

With the server script running, the client script returns:

abc: 123
set-cookie: null

Expected Behavior

In the presence of { credentials: 'include' } I would expect set-cookie headers to not be stripped from the response. The expected output of the client script should be:

abc: 123
set-cookie: hello=world

Environment

Mac OS 12.2.1 Node v16.13.1

Additional context

There is a TODO in Undici’s fetch code where this behavior should be implemented: https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1369-L1375

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:4
  • Comments:16 (11 by maintainers)

github_iconTop GitHub Comments

10reactions
Rich-Harriscommented, May 19, 2022

#1454 was reverted following @ronag’s comment:

I think this landed too early and would prefer we properly investigate and follow the spec

I don’t think there is a spec to follow here though. The spec (referring to 4.7.17.3 of the fetch standard, which leads us 5.2 of RFC 6265) is clearly written for browsers; it assumes that the user agent has a cookie store, which obviously makes no sense for a server that can handle requests from multiple users.

I gather from @KhafraDev that there’s a proposal to add cookieStore options to Request and Response constructors (though the comment doesn’t link to the proposal, just to the proposed CookieStore spec?), and that could be a good solution one day. In the meantime though, being unable to read cookies from requests means that Undici is untenable for many real-world applications. (SvelteKit would like to use Node’s built-in fetch when applications are deployed as Node servers, but for the time being we’re reliant on node-fetch even with Node 18.)

Other implementations have chosen differently. This URL returns a set-cookie: hello=world header — if we fetch it with different implementations, this is what we see:

implementation headers.get('set-cookie')
node-fetch hello=world
Deno hello=world
Cloudflare Workers hello=world
Undici null

Note that it fails in Cloudflare when you’re using Wrangler (whether in --local mode or not), precisely because Miniflare uses Undici: https://github.com/cloudflare/miniflare/issues/183

In the absence of a usable spec, I would argue that following the behaviour that a majority of implementations have agreed upon (and that users expect, as evidenced by the Miniflare issue among others) is the prudent course of action. (Even though headers.get('set-cookie') is problematic because it can smush together multiple headers, this is easily solved in userland with popular packages like set-cookie-parser.)

1reaction
KhafraDevcommented, May 19, 2022

I believe this is a bug that has nothing to do with cookie parsing (etc.) and #1454 presents a valid solution, just need to see what ronag thinks now. 😄

Read more comments on GitHub >

github_iconTop Results From Across the Web

Set cookies for cross origin requests - Stack Overflow
I am setting request and response headers now like crazy now, making sure that they are present in both the request and the...
Read more >
Fetch Standard
The ` Set-Cookie ` header is semantically a response header, so it is not useful on requests. Because ` Set-Cookie ` headers cannot...
Read more >
draft-ietf-httpstate-cookie-10
This document may contain material from IETF Documents or IETF ... To store state, the origin server includes a Set-Cookie header in an...
Read more >
axios samesite=none | The AI Search Engine You Control
The Set-cookie had to have been set with "Same Site=None" to enable ... I reached out to Stripe because I was getting this...
Read more >
Cookies: HTTP State Management Mechanism
Although cookies have many historical infelicities that degrade their security and privacy, the Cookie and Set-Cookie header fields are ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found