w3c/ServiceWorker

Support modifying cookies on an intercepted fetch

Closed this issue · 9 comments

There is an important use case around auth and identity where you may want to intercept fetch requests, detect the cookies are out of date, generate new ones (via a fetch to the server) and then send the original request with the new cookies.

Is that possible with SW today? It seems to me that you can't modify the cookie headers (), and it's unclear whether a currently intercepted request will be modified by a setCookie call.

@eliaswald @slightlyoff

I'm not sure what "detect the cookies are out of date" means, but cookies don't become part of a request until after a service worker has potentially processed it (in http fetch step 3 a service worker gets access to the request, and it isn't until step 4.4 when a request eventually reaches step 12.1 of HTTP-network-or-cache fetch that cookies get applied to the request).

So a SW could definitely modify what cookies will be part of a request, if it had an API to do so. Currently service workers don't have any APIs to read/modify cookies (#707) though.

To expand on the issue: some sites set cookies to expire after short periods for security reasons, but would like to keep a longer term cookie on the client, and then when the short term cookie expires they'd like to make a single "cookie refresh" request with the long term cookie that will provide a new short term cookie which can be added to the original request that had the expired cookies.

If cookies only get added after the SW has processed then would the following possibly work?

  1. Intercept a request to /index.html
  2. Use the new (not yet implemented) getCookies API to inspect the cookies and decide whether they need refreshing
  3. Make a request to the refresh cookies endpoint, which would use headers to set a cookie on the client
  4. Let the request intercepted in 1 go to the network, as at this point the new cookies set in 3 would be added to it

On a high level it sounds like cookies get added after the request leaves the SW so modifying cookies on a request is possible by adding cookies directly to the origin before the request leaves the SW. Let me know if that doesn't sound true though.

@owencm that would work if we had a way to read cookies, but I can't quite get my head around the use-case. If the server knows that cookies need updating, why is there a problem?

Eg:

  1. Request made to server with cookie foo=bar
  2. Server realises that's out of date, and treats it as the correct foo=world
  3. Sends response along with set-cookie foo=world

@jakearchibald the issue is that for some legacy backends (spoiler: there are lots of these out there) it's near impossible to modify all possible endpoints on the server to check and re-issue a new cookie. A much more practical engineering approach is to check in one place in the SW and then hit a single endpoint to refresh the cookies before letting the original fetch proceed.

I know of some specific companies affected by this but don't want to name names. But some identity folk at Google think that if this approach could be made to work then it would be practical for a number of very large sites to keep users logged much longer.

@mkruisselbrink I just tried the following in a service worker:

  1. Intercept a fetch request
  2. Make a new request to an endpoint that includes Set-Cookie with a new cookie
  3. Once that request comes back, wait 1 second and then let the original fetch request go to the server

I've noticed that the second request that goes to the server doesn't include the cookie set by the first request. Is that as expected? Any thoughts about other ways to do this today without setCookie?

@owencm From just reading the various specs I would have expected that to work (the original fetch to include the cookies set by the in-between request). So that's either a bug in the chrome implementation, or I'm misunderstanding the fetch spec.

@owencm Can you test what Firefox does in that case?

@mkruisselbrink @wanderview I couldn't try this in Firefox since I couldn't find any documentation about how to debug service workers there and inspect their console (link?)

I did resolve the issue though. It turns out that the Set-Cookie header is ignored on responses unless the fetch that triggered it specified credentials: 'include', which wasn't my understanding of that option.

I've now got this working as expected, this for now it is possible to hack around the existence of setCookie if you are happy to deal with an additional round trip to the server.

@jakearchibald why Service Worker can't create cookies? Header Set-Cookie created from service worker is removed from the response. What is the reason behind this?

I want to create an API in service worker using Wayne library, and I can't do this properly with JWT refresh and access tokens because cookies are not supported in Service Worker.

Example code:

self.addEventListner('fetch', (event) => {
  const url = new URL(event.request.url);
  if (url.pathname === '/api/login') {
    const headers = {
      "Set-Cookie": "TestCookie=foo; path=/; Max-Age=60;"
      "TestHeader": "foo"
    };
    event.respondWith(new Response('Hello!', { headers }));
  }
});

The Set-Cookie header is removed by the browser, the TestHeader is present.