RFC: Proposal for an asynchronous cookies API


#1

Sketch for an asynchronous cookies API: https://github.com/WICG/async-cookies-api; excerpt from the explainer:

Async cookies API explained

This is a proposal to bring an asynchronous cookie API to scripts running in HTML documents and service workers.

HTTP cookies have, since their origins at Netscape (documentation preserved by archive.org), provided a valuable state-management mechanism for the web.

The synchronous single-threaded script-level document.cookie and <meta http-equiv="set-cookie" ...> interface to cookies has been a source of complexity and performance woes further exacerbated by the move in many browsers from:

  • a single browser process,
  • a single-threaded event loop model, and
  • no general expectation of responsiveness for scripted event handling while processing cookie operations

… to the modern web which strives for smoothly responsive high performance:

  • in multiple browser processes,
  • with a multithreaded, multiple-event loop model, and
  • with an expectation of responsiveness on human-reflex time scales.

On the modern a web a cookie operation in one part of a web application cannot block:

  • the rest of the web application,
  • the rest of the web origin, or
  • the browser as a whole.

Newer parts of the web built in service workers need access to cookies too but cannot use the synchronous, blocking document.cookie and <meta http-equiv="set-cookie" ...> interfaces at all as they both have no document and also cannot block the event loop as that would interfere with handling of unrelated events.

A taste of the proposed change

Although it is tempting to rethink cookies entirely, web sites today continue to rely heavily on them, and the script APIs for using them are largely unchanged over their first decades of usage.

Today writing a cookie means blocking your event loop while waiting for the browser to synchronously update the cookie jar with a carefully-crafted cookie string in Set-Cookie format:

document.cookie =
  '__Secure-COOKIENAME=cookie-value' +
  '; Path=/' +
  '; expires=Fri, 12 Aug 2016 23:05:17 GMT' +
  '; Secure' +
  '; Domain=example.org';
// now we could assume the write succeeded, but since
// failure is silent it is difficult to tell, so we
// read to see whether the write succeeded
var successRegExp =
  /(^|; ?)__Secure-COOKIENAME=cookie-value(;|$)/;
if (String(document.cookie).match(successRegExp)) {
  console.log('It worked!');
} else {
  console.error('It did not work, and we do not know why');
}

What if you could instead write:

cookieStore.set(
  '__Secure-COOKIENAME',
  'cookie-value',
  {
    expires: Date.now() + 24*60*60*1000,
    domain: 'example.org'
  }).then(function() {
    console.log('It worked!');
  }, function(reason) {
    console.error(
      'It did not work, and this is why:',
      reason);
  });
// Meanwhile we can do other things while waiting for
// the cookie store to process the write...

This also has the advantage of not relying on document and not blocking, which together make it usable from service workers, which otherwise do not have cookie access from script.

This proposal also includes a power-efficient monitoring API to replace setTimeout-based polling cookie monitors with cookie change observers.

There is also a document-only polyfill which works in recent Chromium and Google Chrome developer builds with the Experimental JavaScript chrome://flags/#enable-javascript-harmony flag active.


#2

I like the idea of a set() function with name, value, and options - it would be much better than creating the cookie string.

I assume there will be a get(), and remove() or delete() as well? like the Angular JS $cookies API.

Also, what happens with HttpOnly cookies? I assume no access at all, even for Service Workers.


#3

Glad you like it!

Yes, I was trying to keep the excerpt here short but the linked explainer includes get and delete too, along with a CookieObserver for more persistent monitoring from a document and interest registration+an event for service worker cookie change monitoring with no persistent execution context. HttpOnly cookies are writable but not readable - just as with document.cookie - using this interface, regardless of whether the reader is a document or a service worker.

Although there are some similarities to $cookies this API is asynchronous/Promise-based to prevent blocking the event loop while the browser reads or writes its internal cookie storage, which is generally mutex-protected and may be managed by a separate process than the one running the content scripts.


#4

Thanks for your expression of interest on GitHub for moving this API discusson to WICG, @addyosmani! Edit: moved, thanks @cwilso !


#5

As currently explained in the “script-visibility” part of the explainer https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md#script-visibility the proposal would not allow reading of HttpOnly cookies. However, there is an issue tracking the possibility to add this: https://github.com/WICG/async-cookies-api/issues/37


#6

Thanks @bsittler

I’ve added a note on Issue 37, as I’d like to vote against the reading of httpOnly cookies (unless there was a good reason, which I cannot see at the moment).


#7

Thanks @craig.francis ! I think I’m inclined the same way (no HttpOnly cookie reading/monitoring access for scripts) and would rather see dual-cookie session pairs in these cases, but I created the issue because some developers I’ve spoken with have expressed interest in the capability. I’m hoping that Issue 37 can

  • explain the rationale for not permitting this
  • provide enough information that developers who want this capability can learn about viable alternatives and mention any additional useful techniques
  • help us collect data on whether the capability truly is needed and
  • (should the capability prove necessary after all) provide guidance on how best to restrict this capability so that any resulting security vulnerability would be minimized

#8

That sounds good to me.

And I would be intrigued to see what their use cases would be - and hopefully we can find solutions that keep everyone happy (ish).


#9

In case anyone interested finds the discussion here at WICG Discourse, I have started a Blink intent-to-implement discussion thread for this proposal.


#10

Repo is renamed to http://wicg.github.io/cookie-store/ to increase future findability should this proposal reach standardization and adoption; the new name reflects the name by which web developers are expected to know the API.