playwright icon indicating copy to clipboard operation
playwright copied to clipboard

[Feature]: Support Partitioned cookies (CHIPS) in `storageState`

Open estyrke opened this issue 8 months ago • 3 comments

🚀 Feature Request

I'm trying to implement the new Partitioned flag for our backend's cookies (see https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies).

With this I'm hoping to support Safari and upcoming cookie-blocking chrome versions in the use case where our frontend runs on another domain than our backend (e.g. during e2e testing on preview builds).

My auth setup looks like this:

  await request.post(`${apiUrl}/latest/auth/login`, {
    data: {
      username: email,
      password,
    },
  })
  await request.storageState({ path: authFile })

But when the cookies come back with a Partitioned flag on them, this isn't represented in the authFile, so when I use this storageState in my tests I have two problems:

  1. Browsers that only send Partitioned cookies in cross-site requests won't send this auth cookie if the apiUrl is on a different domain than the frontend.
  2. When I try to log out in a test, the (empty, expired) cookie that comes back is Partitioned, but the auth cookie from the storageState is not Partitioned, so the browser thinks those cookies are not the same and keeps the auth cookie from the storageState instead of dropping it. I can solve this by removing both unpartitioned and partitioned cookies in my logout endpoint though.

Example

  1. Hit a login endpoint which uses Partitioned cookies to return an authentication token.
  2. use request.storageState({ path: authFile }) to persist the storage state, taking the Partitioned flag into account
  3. use the storageState test option to load the storage state, taking the Partitioned flag into account. The browser's cookie storage will now be the same as if I had done the authentication in each test without storageState.

Motivation

Without this, it's impossible to use storageState to accurately represent the actual browser behaviour when Partitioned cookies are in play.

estyrke avatar Apr 14 '25 12:04 estyrke

Here is an example web-site for testing the CHIPS cookie behavior: https://cookie-server.azurewebsites.net/

yury-s avatar Jun 06 '25 18:06 yury-s

Here is the behavior I see on macOS 15.5 with the above web page:

Browser Cookie Behavior (Origin 1 → Origin 2 → Origin 1) Cookie Behavior (Origin 2 → Origin 1)
Chrome 137 frame-non-partitioned, frame-partitioned, top-level-non-partitioned frame-non-partitioned, frame-partitioned, top-level-non-partitioned
Firefox 139 frame-non-partitioned, frame-partitioned frame-non-partitioned, frame-partitioned
Safari 18.5 frame-non-partitioned, frame-partitioned, top-level-non-partitioned, top-level-partitioned no cookies sent to the server

yury-s avatar Jun 09 '25 18:06 yury-s

On further investigation, it turns out that the partitioned cookies did work in Safari 18.4 but were disable in 18.5, see this commit: https://commits.webkit.org/295121@main. This is not mentioned in 18.5 release notes. The setting from the screenshot below was there in 18.4 and is gone in 18.5:

Image

yury-s avatar Jun 09 '25 18:06 yury-s

The functionality works in Chromium. You can test the server behavior with that. We will get back to it once WebKit settles on the CHIPS behavior, so far it has been reverted and going back and forth.

yury-s avatar Aug 26 '25 23:08 yury-s