Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist Cookies between redirects #3784

Open
OZZlE opened this issue Oct 29, 2024 · 6 comments
Open

Persist Cookies between redirects #3784

OZZlE opened this issue Oct 29, 2024 · 6 comments
Labels
enhancement New feature or request

Comments

@OZZlE
Copy link

OZZlE commented Oct 29, 2024

We have an Api that you need to call on endpoint A, it sets cookies and redirects to B (and you cannot call B directly) but undici looses the cookies so the Api call fails.

(Update: both A and B live on the same origins but diffent paths and the cookie path is set on /)

fetch(
        "https://example.com/api",
        {
            method: "POST",
            credentials: 'include', // this guy should probably make this assumption if I understood the spec correctly
            redirect: "follow", // together with him
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
            body: urlencoded.toString(),
        }
    )

I also considered:

import { fetch as uFetch } from 'undici';
import fetchCookie from 'fetch-cookie';
const fetch = fetchCookie(uFetch);

However on Win11 I want to use SSL certs which is poorly implemented in windows so I have to use this syntax:

const ca = (await import('win-ca')).default;
const rootCAs = []
// Fetch all certificates in PEM format
ca({
    format: ca.der2.pem,
    ondata: buf => rootCAs.push(buf.toString())
})
    
async function uWinCaFetch(url) {
    const dispatcher = new Agent({
        connect: {
            ca: rootCAs, // Pass all root certificates
        }
    });
    return request(url, { dispatcher });
}

But trying to wrap that with fetchCookie like: const fetch = fetchCookie(uWinCaFetch); only becomes:

file:///C:/ws/projects/my-card/node_modules/fetch-cookie/esm/index.js:129
const cookieString = response.headers.get("set-cookie");
                                        ^

TypeError: response.headers.get is not a function
    at getCookiesFromResponse (file:///C:/ws/projects/my-card/node_modules/fetch-cookie/esm/index.js:129:41)
    at fetchCookieWrapper (file:///C:/ws/projects/my-card/node_modules/fetch-cookie/esm/index.js:145:21)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async GET (file:///C:/ws/projects/my-card/test.mjs:62:9)
    at async file:///C:/ws/projects/my-card/test.mjs:92:1

Additional context

@ronag
Copy link
Member

ronag commented Oct 29, 2024

@KhafraDev

@KhafraDev
Copy link
Member

If A and B are different origins, the spec tells us to remove cookies on cross-origin redirects.

@OZZlE
Copy link
Author

OZZlE commented Oct 30, 2024

If A and B are different origins, the spec tells us to remove cookies on cross-origin redirects.

Yep, in my case the hostname is identical, path should not matter unless the cookie was set on a specific path other than /, our cookies also use / as path

@KhafraDev
Copy link
Member

"Same origin" in this case requires the protocol, hostname, and port to be identical. If this is true, I need a reproducible sample.

@OZZlE
Copy link
Author

OZZlE commented Oct 31, 2024

They are identical, our website is behind login. That using fetchCookie solves the issue should be proof enough that the issue exists. I will get back to you if I can find time to set up an example, it might take some time to implement.

Times like these node.js feels a bit imature compared to many of the older web backends.

@KhafraDev
Copy link
Member

I may have been concentrating on your same origin comment too much since we've had similar reports in the past - undici does not implement a cookie jar.

import { once } from 'node:events'
import { createServer } from 'node:http'

const server = createServer((req, res) => {
  if (req.url === '/path1') {
    res.writeHead(302, undefined, {
      location: '/path2',
      'set-cookie': 'a=b'
    })
    res.end()
  } else {
    console.log('ok')
    console.log(req.headers)
    res.end()
  }
}).listen(0)

await once(server, 'listening')

const v = await fetch(`http://localhost:${server.address().port}/path1`)

console.log(v.headers.getSetCookie()) // empty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants
@OZZlE @ronag @KhafraDev and others