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

Unable to create Partitioned cookie #5275

Open
benfosterlitmos opened this issue Oct 10, 2023 · 21 comments
Open

Unable to create Partitioned cookie #5275

benfosterlitmos opened this issue Oct 10, 2023 · 21 comments

Comments

@benfosterlitmos
Copy link

The Partitioned attribute is not set when passing the option to res.cookie().

https://developer.chrome.com/docs/privacy-sandbox/third-party-cookie-phase-out/#partitioned-cookies

@vladimiratanasov
Copy link

vladimiratanasov commented Oct 12, 2023

I am facing the same issue. Looking at the code, the project is using jshttp/cookie package to serialize the cookie to a string, and this downstream package does not support the partitioned flag. https://github.com/jshttp/cookie/blob/master/index.js#L111

There is a PR already to adopt this flag, let's hope for a quick turnaround jshttp/cookie#151

And another PR, with a more active maintainer jshttp/cookie#153.

@vladimiratanasov
Copy link

@dougwilson now that the partitioned property was adopted by jshttp/cookie, can it be updated here as well?

@andrewterry12
Copy link

Also interested in this. There is a time crunch as Google Chrome will begin blocking 1% of 3rd party cookies without this attribute in Q1 2024

@dougwilson
Copy link
Contributor

Hello, our dependency recently added this, so it will get pulled in here in the next version. Apologies as it is currently a holiday time where I am, but will get a release spun up to include this asap.

@honohunter
Copy link

@dougwilson do you have any timeline for this upcoming release?

@dougwilson
Copy link
Contributor

I am working on it right now, so it should be out within a few days at most 👍

@gorets
Copy link

gorets commented Dec 9, 2023

Do you have a problem?

@dougwilson
Copy link
Contributor

I'm sorry, I had to travel due to a death in the family and I keep getting bogus security vulnerability reports I have to keep triaging. I just got yet another one 30 mins ago. I am working as hard as possible. If I do not assess these and debate with the reporters or fix, they will file a CVE with no fix version and then chaos will ensue from everyone getting security reports, creating a bigger mess. I am working on express stuff right now even.

@vojvodics
Copy link

For anyone facing the same issue that needs the update before Express fixes it, there is a workaround:

  1. Fix the version of the cookie package in package.json to 0.6.0. (Note: this may be unsafe to do if other packages depend on some lower version of the package. Do at your own risk)
"resolutions": {
  "cookie": "0.6.0"
}
  1. If using typescript, add the following override
declare module "express-serve-static-core" {
  export interface CookieOptions {
    partitioned?: boolean;
  }
}
  1. You should be able to use partitioned option
res.cookie("cookie-name", "cookie-value", { partitioned: true });
image

@morsssss
Copy link

@dougwilson sorry to hear about the difficulties you're going through. I would volunteer to boost the cookie dependency to 0.6.0, but I imagine there's more to do to make sure nothing breaks. Let me know though if I can help!

@imki123
Copy link

imki123 commented Jan 22, 2024

In my case, module "express" is working.

import { CookieOptions } from 'express'

declare module "express" {
  export interface CookieOptions {
    partitioned?: boolean;
  }
}

// something todo ...

It's working for me. I added secure: true, sameSite: 'none', partitioned: true.

const cookieOption = {
    httpOnly: true,
    secure: true,
    sameSite: 'none',
    partitioned: true,
  }

res.cookie(key, value, cookieOption)

@PascalPlantey
Copy link

PascalPlantey commented Jan 26, 2024

Not working for me. I've set

  "overrides": {
    "cookie": "0.6.0"
  },

in package.json, and checked that the deployed production cookie version is 0.6.0 in node modules. I'm using cookie-parser and express

  const sessionConfig = {
    secret: process.env.COOKIE_SECRET,                                        // Secret utilisé par passport
    resave: false,
    saveUninitialized: false,
    cookie: {
      maxAge: 7 * 24 * 60 * 60 * 1000,                                        // 7 days : 7 * 24 * 60 * 60 * 1000
      resave: false,
      httpOnly: false,
      secure: PRODUCTION ? true : false,
      sameSite: PRODUCTION ? 'none' : '',
      partitioned: true
    },
  };

  app.set('trust proxy', 1);                                                  // Don't forward proxy but client's ip
  app.use(session({
    store: new pgSession({ pool: partnersDB.pool, }),                         // Une session DB à part sur le même pool
    ...sessionConfig,
  }));

but the cookies are still not partitioned. Is this due to cookie-parser or something else?

@vojvodics
Copy link

@PascalPlantey If you're using the https://github.com/expressjs/session package, they seem to be passing the cookie options manually (see https://github.com/expressjs/session/blob/master/session/cookie.js#L117-L138). So it would need to be fixed there

@dougwilson
Copy link
Contributor

We are working the cookie update through the dependencies currently. The cookie-session was updated recently, and express-session is here right behind, and express itself as a wip pr for it so should be out soon too.

@PascalPlantey
Copy link

@vojvodics I'm using 'express' 4.15.2 and express-session 1.17.1, and I think the cookie.js in express-session should not hide the partitioned attribute:

var Cookie = module.exports = function Cookie(options) {
  this.path = '/';
  this.maxAge = null;
  this.httpOnly = true;

  if (options) {
    if (typeof options !== 'object') {
      throw new TypeError('argument options must be a object')
    }

    for (var key in options) {
      if (key !== 'data') {
        this[key] = options[key]
      }
    }
  }

  if (this.originalMaxAge === undefined || this.originalMaxAge === null) {
    this.originalMaxAge = this.maxAge
  }
};

@PascalPlantey
Copy link

PascalPlantey commented Jan 27, 2024

@vojvodics you are correct, I found some code below in the source, suppressing the partitioned attribute

  get data() {
    return {
      originalMaxAge: this.originalMaxAge
      , expires: this._expires
      , secure: this.secure
      , httpOnly: this.httpOnly
      , domain: this.domain
      , path: this.path
      , sameSite: this.sameSite
    }
  },

@dougwilson
Copy link
Contributor

As an update express-session has been updated with the support now. A new minor of express is being queued up with the new cookie attribute for res.cookie now.

@peter1357908
Copy link

For anyone facing the same issue that needs the update before Express fixes it, there is a workaround:

  1. Fix the version of the cookie package in package.json to 0.6.0. (Note: this may be unsafe to do if other packages depend on some lower version of the package. Do at your own risk)
"resolutions": {
  "cookie": "0.6.0"
}
  1. If using typescript, add the following override
declare module "express-serve-static-core" {
  export interface CookieOptions {
    partitioned?: boolean;
  }
}
  1. You should be able to use partitioned option
res.cookie("cookie-name", "cookie-value", { partitioned: true });
image

Confirming that this works. I am using cookie-parser with npm, and adding the following to package.json and running npm install resolved the issue. Now I can silence Chrome's warnings about third-party cookies...

"overrides": {
    "cookie": "0.6.0"
}

@mikegwhit
Copy link

mikegwhit commented Feb 28, 2024

I added some notes on adapting Express.js to HTTP2 or to reevaluate the SPDY breakages.. Add this one to the list

It seems more reliable in the interim to suggest to others to write to headers directly.. will update here shortly with pseudocode but this is ChatGPT's version:


  // Define the cookie string manually
  const cookieValue = 'your_cookie_value';
  const cookieOptions = 'Expires=Wed, 21 Oct 2025 07:28:00 GMT; Path=/; Secure; HttpOnly';
  const cookieString = `myCookieName=${cookieValue}; ${cookieOptions}`;

  // Set the cookie using the Set-Cookie header
  res.setHeader('Set-Cookie', cookieString);

or my use case (adapt it to your own):

        if (typeof jwtToSet == 'object') {
            jwtToSet = JSON.stringify(jwtToSet);
        }
        if (req.hostname && req.hostname.length > 0) {
            const cookieValue = `saasworks-session=${jwtToSet}`;
            // Construct the cookie options
            let cookieOptions = [
                `Domain=.${req.hostname}`,
                'HttpOnly',
                'Secure',
                'SameSite=Lax',
                'Partitioned',
            ];
            if (logout) {
                cookieOptions.push('Expires=Thu, 01 Jan 1970 00:00:00 GMT');
            }
            cookieOptions = cookieOptions.join('; ');
            // Combine the cookie value and options
            const cookieString = `${cookieValue}; ${cookieOptions}`;

            console.info('Setting cookie', cookieString);
            // Set the cookie using the Set-Cookie header
            res.setHeader('Set-Cookie', cookieString);
        }

if you want to set multiple cookies, you use an array of cookieStrings

@okay-head
Copy link

Has this issue resolved yet? I'm using Express 4.18.2 and am not using any cookie packages, except cookie-parser, which has nothing to do with sending requests.

res.cookie(... , {partitioned: true})

However when I inspect the cookie in the network tab, I see nothing

image

This is really getting to me, cors has gotta be the biggest PITA

@okay-head
Copy link

Update: I've found a workaround

Instead of using res.cookie() I've resorted to using the native res.setHeader() coupled with the jshttp cookie.

const cookie = require('cookie')

// ...

res.setHeader(
    'Set-Cookie',
    cookie.serialize('session_id', String(session_id), {
        path: '/',
        httpOnly: true,
        maxAge: 86400,
        secure: true,
        sameSite: 'none',
        partitioned: true,
    })
)

I had to use the cookie package, because there's not enough documentation available for res.setHeader() esp no instructions for passing multiple options parameters and that's crazy.

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

No branches or pull requests