express icon indicating copy to clipboard operation
express copied to clipboard

Unable to create Partitioned cookie

Open benfosterlitmos opened this issue 1 year ago • 22 comments

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

benfosterlitmos avatar Oct 10 '23 23:10 benfosterlitmos

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 https://github.com/jshttp/cookie/pull/151

And another PR, with a more active maintainer https://github.com/jshttp/cookie/pull/153.

vladimiratanasov avatar Oct 12 '23 13:10 vladimiratanasov

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

vladimiratanasov avatar Nov 16 '23 13:11 vladimiratanasov

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

andrewterry12 avatar Nov 21 '23 18:11 andrewterry12

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.

dougwilson avatar Nov 21 '23 18:11 dougwilson

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

honohunter avatar Dec 04 '23 13:12 honohunter

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

dougwilson avatar Dec 04 '23 13:12 dougwilson

Do you have a problem?

gorets avatar Dec 09 '23 20:12 gorets

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.

dougwilson avatar Dec 10 '23 00:12 dougwilson

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

vojvodics avatar Dec 12 '23 10:12 vojvodics

@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!

morsssss avatar Jan 19 '24 19:01 morsssss

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)

imki123 avatar Jan 22 '24 15:01 imki123

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?

PascalPlantey avatar Jan 26 '24 12:01 PascalPlantey

@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

vojvodics avatar Jan 26 '24 13:01 vojvodics

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.

dougwilson avatar Jan 26 '24 13:01 dougwilson

@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 avatar Jan 26 '24 13:01 PascalPlantey

@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
    }
  },

PascalPlantey avatar Jan 27 '24 12:01 PascalPlantey

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.

dougwilson avatar Jan 29 '24 23:01 dougwilson

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"
}

peter1357908 avatar Feb 01 '24 06:02 peter1357908

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

mikegwhit avatar Feb 28 '24 22:02 mikegwhit

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 avatar May 07 '24 04:05 okay-head

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.

okay-head avatar May 07 '24 13:05 okay-head

Hi all, i am just wondering if there is time schedule for release of this in res.cookie it's been a while and just wondering if there is a solution already out there.

Many thanks

Numel2020 avatar Jun 10 '24 13:06 Numel2020