# Cookie Store API

## Draft Community Group Report, 1 January 1970

This version:
  https://wicg.github.io/cookie-store/
Test Suite:
  https://github.com/web-platform-tests/wpt/tree/master/cookie-store
Editors:
  Victor Costan (Google Inc.)
  Joshua Bell (Google Inc.)
Former Editor:
  Raymond Toy (Google Inc.)

Copyright © 1970 the Contributors to the Cookie Store API Specification, published by the Web Platform Incubator Community Group under the W3C Community Contributor License Agreement (CLA). A human-readable summary is available.

## Abstract

An asynchronous Javascript cookies API for documents and workers

## Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

## 1. Introduction

This section is non-normative.

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` 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 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` interface at all as they both have no `document` and also cannot block the event loop as that would interfere with handling of unrelated events.

### 1.1. 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.

### 1.2. Summary

This proposal outlines an asynchronous API using Promises/async functions for the following cookie operations:

- write (or "set") and delete (or "expire") cookies

- read (or "get") script-visible cookies

  - ... including for specified in-scope request paths in service worker contexts

- monitor script-visible cookies for changes using `CookieChangeEvent`

  - ... in long-running script contexts (e.g. `document`)

  - ... after registration during the `InstallEvent` in ephemeral service worker contexts

  - ... again including for script-supplied in-scope request paths in service worker contexts

#### 1.2.1. Script visibility

A cookie is script-visible when it is in-scope and does not have the `HttpOnly` cookie flag.

#### 1.2.2. Motivations

Some service workers need access to cookies but cannot use the synchronous, blocking `document.cookie` interface as they both have no `document` and also cannot block the event loop as that would interfere with handling of unrelated events.

A new API may also provide a rare and valuable chance to address some outstanding cross-browser incompatibilities and bring divergent specs and user-agent behavior into closer correspondence.

A well-designed and opinionated API may actually make cookies easier to deal with correctly from scripts, with the potential effect of reducing their accidental misuse. An efficient monitoring API, in particular, can be used to replace power-hungry polling cookie scanners.

The API must interoperate well enough with existing cookie APIs (HTTP-level, HTML-level and script-level) that it can be adopted incrementally by a large or complex website.

#### 1.2.3. Opinions

This API defaults cookie paths to `/` for cookie write operations, including deletion/expiration. The implicit relative path-scoping of cookies to `.` has caused a lot of additional complexity for relatively little gain given their security equivalence under the same-origin policy and the difficulties arising from multiple same-named cookies at overlapping paths on the same domain. Cookie paths without a trailing `/` are treated as if they had a trailing `/` appended for cookie write operations. Cookie paths must start with `/` for write operations, and must not contain any `..` path segments. Query parameters and URL fragments are not allowed in paths for cookie write operations.

URLs without a trailing `/` are treated as if the final path segment had been removed for cookie read operations, including change monitoring. Paths for cookie read operations are resolved relative to the default read cookie path.

This API defaults cookies to "Secure" when they are written from a secure web origin. This is intended to prevent unintentional leakage to unsecured connections on the same domain. Furthermore it disallows (to the extent permitted by the browser implementation) creation or modification of `Secure-`flagged cookies from unsecured web origins and enforces special rules for the __Host- and __Secure- cookie name prefixes.

This API defaults cookies to "Domain"-less, which in conjunction with "Secure" provides origin-scoped cookie behavior in most modern browsers. When practical the `__Host-` cookie name prefix should be used with these cookies so that cooperating browsers origin-scope them.

Serialization of expiration times for non-session cookies in a special cookie-specific format has proven cumbersome, so this API allows JavaScript Date objects and numeric timestamps (milliseconds since the beginning of the Unix epoch) to be used instead. The inconsistently-implemented Max-Age parameter is not exposed, although similar functionality is available for the specific case of expiring a cookie.

Cookies without U+003D (=) code points in their HTTP Cookie header serialization are treated as having an empty name, consistent with the majority of current browsers. Cookies with an empty name cannot be set using values containing U+003D (=) code points as this would result in ambiguous serializations in the majority of current browsers.

Internationalized cookie usage from scripts has to date been slow and browser-specific due to lack of interoperability because although several major browsers use UTF-8 interpretation for cookie data, historically Safari and browsers based on WinINet have not. This API mandates UTF-8 interpretation for cookies read or written by this API.

Use of cookie-change-driven scripts has been hampered by the absence of a power-efficient (non-polling) API for this. This API provides observers for efficient monitoring in document contexts and interest registration for efficient monitoring in service worker contexts.

Scripts should not have to write and then read "test cookies" to determine whether script-initiated cookie write access is possible, nor should they have to correlate with cooperating server-side versions of the same write-then-read test to determine that script-initiated cookie read access is impossible despite cookies working at the HTTP level.

#### 1.2.4. Compatiblity

Some user-agents implement non-standard extensions to cookie behavior. The intent of this specification, though, is to first capture a useful and interoperable (or mostly-interoperable) subset of cookie behavior implemented across modern browsers. As new cookie features are specified and adopted it is expected that this API will be extended to include them. A secondary goal is to converge with `document.cookie` behavior and the http cookie specification. See https://github.com/whatwg/html/issues/804 and https://inikulin.github.io/cookie-compat/ for the current state of this convergence.

Differences across browsers in how bytes outside the printable-ASCII subset are interpreted has led to long-lasting user- and developer-visible incompatibilities across browsers making internationalized use of cookies needlessly cumbersome. This API requires UTF-8 interpretation of cookie data and uses `USVString` for the script interface, with the additional side-effects that subsequent uses of `document.cookie` to read a cookie read or written through this interface and subsequent uses of `document.cookie` to update a cookie previously read or written through this interface will also use a UTF-8 interpretation of the cookie data. In practice this will change the behavior of `WinINet`-based user agents and Safari but should bring their behavior into concordance with other modern user agents.

### 1.3. Querying Cookies

Both documents and service workers access the same query API, via the `cookieStore` property on the global object.

The `get()` and `getAll()` methods on `CookieStore` are used to query cookies. Both methods return promises. Both methods take the same arguments, which can be either:

- a name, or

- a optional dictionary of options

The `get()` method is essentially a form of `getAll()` that only returns the first result.

Reading a cookie:

    try {
      const cookie = await cookieStore.get('session_id');
      if (cookie) {
        console.log(`Found ${cookie.name} cookie: ${cookie.value}`);
      } else {
        console.log('Cookie not found');
      }
    } catch (e) {
      console.error(`Cookie store error: ${e}`);
    }

Reading multiple cookies:

    try {
      const cookies = await cookieStore.getAll({
        name: 'session_',
        matchType: 'starts-with',
      });
      for (const cookie of cookies)
        console.log(`Result: ${cookie.name} = ${cookie.value}`);
    } catch (e) {
      console.error(`Cookie store error: ${e}`);
    }

Service workers can obtain the list of cookies that would be sent by a fetch to any URL under their scope.

Read the cookies for a specific URL (in a service worker):

    await cookieStore.getAll({url: '/admin'});

Documents can only obtain the cookies at their current URL. In other words, the only valid `url` value in Document contexts is the document’s URL.

The objects returned by `get()` and `getAll()` contain all the relevant information in the cookie store, not just the name and the value as in the older `document.cookie` API.

Accessing all the cookie data:

    await cookie = cookieStore.get('session_id');
    console.log(`Cookie scope - Domain: ${cookie.domain} Path: ${cookie.path}`);
    if (cookie.expires === null) {
      console.log('Cookie expires at the end of the session');
    } else {
      console.log(`Cookie expires at: ${cookie.expires}`);
    }
    if (cookie.secure)
      console.log('The cookie is restricted to secure origins');

### 1.4. Modifying Cookies

Both documents and service workers access the same modification API, via the `cookieStore` property on the global object.

Cookies are created or modified (written) using the `set()` method.

Write a cookie:

    try {
      await cookieStore.set('opted_out', '1');
    } catch (e) {
      console.error(`Failed to set cookie: ${e}`);
    }

The `set()` call above is a shorthand for the following:

    await cookieStore.set({
      name: 'opted_out',
      value: '1',
      expires: null,  // session cookie

      // By default, cookies are scoped at the current domain.
      domain: (new URL(self.location.href)).hostname,
      path: '/',

      // Creates secure cookies by default on secure origins.
      secure: true,
    });

Cookies are deleted (expired) using the `delete()` method.

Delete a cookie:

    try {
      await cookieStore.delete('session_id');
    } catch (e) {
      console.error(`Failed to delete cookie: ${e}`);
    }

Under the hood, deleting a cookie is done by changing the cookie’s expiration date to the past, which still works.

Deleting a cookie by changing the expiry date:

    try {
      const one_day_ms = 24 * 60 * 60 * 1000;
      await cookieStore.set('session_id', 'value will be ignored',
                            { expires: Date.now() - one_day_ms });
    } catch (e) {
      console.error(`Failed to delete cookie: ${e}`);
    }

### 1.5. Monitoring Cookies

To avoid polling, it is possible to observe changes to cookies.

In documents, `change` events are fired for all relevant cookie changes.

Register for `change` events in documents:

    cookieStore.addEventListener('change', event => {
      console.log(`${event.changed.length} changed cookies`);
      for (const cookie in event.changed)
        console.log(`Cookie ${cookie.name} changed to ${cookie.value}`);

    console.log(`${event.deleted.length} deleted cookies`);
      for (const cookie in event.deleted)
        console.log(`Cookie ${cookie.name} deleted`);
    });

Service workers have to subscribe for events during the install stage, and start receiving `cookiechange` events when activated.

Register for `cookiechange` events in a service worker:

    self.addEventListener('install', event => {
      event.waitFor(async () => {
        await cookieStore.subscribeToChanges([{
          name: 'session',  // Get change events for session-related cookies.
          matchType: 'starts-with',  // Matches session_id, session-id, etc.
        }]);
      });
    });

    self.addEventListener('cookiechange', event => {
      // The event has |changed| and |deleted| properties with
      // the same semantics as the Document events.
      console.log(`${event.changed.length} changed cookies`);
      console.log(`${event.deleted.length} deleted cookies`);
    });

Calls to `subscribeToChanges()` are cumulative, so that independently maintained modules or libraries can set up their own subscriptions. As expected, a service worker's subscriptions are persisted for with the service worker registration.

Subscriptions can use the same options as `get()` and `getAll()`. The complexity of fine-grained subscriptions is justified by the cost of dispatching an irrelevant cookie change event to a service worker, which is is much higher than the cost of dispatching an equivalent event to a window. Specifically, dispatching an event to a service worker might require waking up the worker, which has a significant impact on battery life.

The `getChangeSubscriptions()` allows a service worker to introspect the subscriptions that have been made.

Checking change subscriptions:

       const subscriptions = await cookieStore.getChangeSubscriptions();
       for (const sub of subscriptions) {
         console.log(sub.name, sub.url, sub.matchType);
       }

## 2. Concepts

### 2.1. Cookie

A cookie is normatively defined for user agents by Cookies: HTTP State Management Mechanism §User Agent Requirements.

Per Cookies: HTTP State Management Mechanism §Storage Model, a cookie has the following fields: name, value, expiry-time, domain, path, creation-time, last-access-time, persistent-flag, host-only-flag, secure-only-flag, http-only-flag, same-site-flag.

### 2.2. Cookie Store

A cookie store is normatively defined for user agents by Cookies: HTTP State Management Mechanism §User Agent Requirements.

When any of the following conditions occur for a cookie store, perform the steps to process cookie changes.

- A newly-created cookie is inserted into the cookie store.

- A user agent evicts expired cookies from the cookie store.

- A user agent removes excess cookies from the cookie store.

How about when "the current session is over" for non-persistent cookies?

### 2.3. Extensions to Service Worker

[Service-Workers] defines service worker registration, which this specification extends.

A service worker registration has an associated cookie change subscription list which is a list; each member is a cookie change subscription. A cookie change subscription is a tuple of name, url, and matchType.

## 3. The `CookieStore` Interface

    [Exposed=(ServiceWorker,Window),
     SecureContext]
    interface CookieStore : EventTarget {
      Promise<CookieListItem?> get(USVString name);
      Promise<CookieListItem?> get(optional CookieStoreGetOptions options = {});

      Promise<CookieList> getAll(USVString name);
      Promise<CookieList> getAll(optional CookieStoreGetOptions options = {});

      Promise<void> set(USVString name, USVString value,
                        optional CookieStoreSetOptions options = {});
      Promise<void> set(CookieStoreSetExtraOptions options);

      Promise<void> delete(USVString name);
      Promise<void> delete(CookieStoreDeleteOptions options);

      [Exposed=ServiceWorker]
      Promise<void> subscribeToChanges(sequence<CookieStoreGetOptions> subscriptions);

      [Exposed=ServiceWorker]
      Promise<sequence<CookieStoreGetOptions>> getChangeSubscriptions();

      [Exposed=Window]
      attribute EventHandler onchange;
    };

    enum CookieMatchType {
      "equals",
      "starts-with"
    };

    dictionary CookieStoreGetOptions {
      USVString name;
      USVString url;
      CookieMatchType matchType = "equals";
    };

    enum CookieSameSite {
      "strict",
      "lax",
      "none"
    };

    dictionary CookieStoreSetOptions {
      DOMTimeStamp? expires = null;
      USVString? domain = null;
      USVString path = "/";
      boolean secure = true;
      CookieSameSite sameSite = "strict";
    };

    dictionary CookieStoreSetExtraOptions : CookieStoreSetOptions {
      required USVString name;
      required USVString value;
    };

    dictionary CookieStoreDeleteOptions {
      required USVString name;
      USVString? domain = null;
      USVString path = "/";
    };

    dictionary CookieListItem {
      required USVString name;
      USVString value;
      USVString? domain = null;
      USVString path = "/";
      DOMTimeStamp? expires = null;
      boolean secure = true;
      CookieSameSite sameSite = "strict";
    };

    typedef sequence<CookieListItem> CookieList;

### 3.1. The `get()` method

cookie = await cookieStore . `get`(name)
cookie = await cookieStore . `get`(options)
  Returns a promise resolving to the first in-scope script-visible value for a given cookie name (or other options). In a service worker context this defaults to the path of the service worker’s registered scope. In a document it defaults to the path of the current document and does not respect changes from `replaceState()` or `document.domain`.

The `get(name)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. Let list be the results of running query cookies with url and name.

   2. If list is failure, then reject p with a `TypeError` and abort these steps.

   3. If list is empty, then resolve p with undefined.

   4. Otherwise, resolve p with the first item of list.

6. Return p.

The `get(options)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. If options’ `url` dictionary member is present, then run these steps:

   1. Let parsed be the result of parsing options’ `url` dictionary member with the context object's relevant settings object's API base URL.

   2. If the current global object is a `Window` object and parsed does not equal url, then return a promise rejected with a `TypeError`.

   3. If parsed’s origin and url’s origin are not the same origin, then return a promise rejected with a `TypeError`.

   4. Set url to parsed.

5. Let p be a new promise.

6. Run the following steps in parallel:

   1. Let list be the results of running query cookies with url, options’ `name` dictionary member (if present), and options’ `matchType` dictionary member.

   2. If list is failure, then reject p with a `TypeError` and abort these steps.

   3. If list is empty, then resolve p with undefined.

   4. Otherwise, resolve p with the first item of list.

7. Return p.

### 3.2. The `getAll()` method

cookies = await cookieStore . `getAll`(name)
cookies = await cookieStore . `getAll`(options)

  Returns a promise resolving to the all in-scope script-visible value for a given cookie name (or other options). In a service worker context this defaults to the path of the service worker’s registered scope. In a document it defaults to the path of the current document and does not respect changes from `replaceState()` or `document.domain`.

The `getAll(name)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. Let list be the results of running query cookies with url and name.

   2. If list is failure, then reject p with a `TypeError`.

   3. Otherwise, resolve p with list.

6. Return p.

The `getAll(options)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. If options’ `url` dictionary member is present, then run these steps:

   1. Let parsed be the result of parsing options’ `url` dictionary member with the context object's relevant settings object's API base URL.

   2. If the current global object is a `Window` object and parsed does not equal url, then return a promise rejected with a `TypeError`.

   3. If parsed’s origin and url’s origin are not the same origin, then return a promise rejected with a `TypeError`.

   4. Set url to parsed.

5. Let p be a new promise.

6. Run the following steps in parallel:

   1. Let list be the results of running query cookies with url, options’ `name` dictionary member (if present), and options’ `matchType` dictionary member.

   2. If list is failure, then reject p with a `TypeError`.

   3. Otherwise, resolve p with list.

7. Return p.

### 3.3. The `set()` method

await cookieStore . `set`(name, value)
await cookieStore . `set`(options)
  Writes (creates or modifies) a cookie.

  The options default to:

  - Path: `/`

  - Domain: same as the domain of the current document or service worker’s location

  - No expiry date

  - Secure flag: set (cookie only transmitted over secure protocol)

  - SameSite: strict

The `set(name, value, options)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. Let r be the result of running set a cookie with url, name, value, options’ `expires` dictionary member, options’ `domain` dictionary member, options’ `path` dictionary member, options’ `secure` dictionary member, and options’ `sameSite` dictionary member.

   2. If r is failure, then reject p with a `TypeError` and abort these steps.

   3. Resolve p with undefined.

6. Return p.

The `set(options)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. Let r be the result of running set a cookie with url, options’ `name` dictionary member, options’ `value` dictionary member, options’ `expires` dictionary member, options’ `domain` dictionary member, options’ `path` dictionary member, options’ `secure` dictionary member, and options’ `sameSite` dictionary member.

   2. If r is failure, then reject p with a `TypeError` and abort these steps.

   3. Resolve p with undefined.

6. Return p.

### 3.4. The `delete()` method

await cookieStore . `delete`(name)
await cookieStore . `delete`(options)
  Deletes (expires) a cookie with the given name or name and optional domain and path.

The `delete(name)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. Let r be the result of running delete a cookie with url, name, null, "`/`", true, and "`strict`".

   2. If r is failure, then reject p with a `TypeError` and abort these steps.

   3. Resolve p with undefined.

6. Return p.

The `delete(options)` method, when invoked, must run these steps:

1. Let origin be the current settings object's origin.

2. If origin is an opaque origin, then return a promise rejected with a "`SecurityError`" `DOMException`.

3. Let url be the current settings object's creation URL.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. Let r be the result of running delete a cookie with url, options’ `name` dictionary member, options’ `domain` dictionary member, and options’ `path` dictionary member.

   2. If r is failure, then reject p with a `TypeError` and abort these steps.

   3. Resolve p with undefined.

6. Return p.

### 3.5. The `subscribeToChanges()` method

await cookieStore . `subscribeToChanges`(subscriptions)
  This method can only be called during a Service Worker install phase.

  Once subscribed, notifications are delivered as "`cookiechange`" events fired against the Service Worker's global scope:

The `subscribeToChanges(subscriptions)` method, when invoked, must run these steps:

1. Let serviceWorker be the context object's global object's service worker.

2. If serviceWorker’s state is not installing, then return a promise rejected with a `TypeError`.

3. Let registration be serviceWorker’s associated containing service worker registration.

4. Let p be a new promise.

5. Run the following steps in parallel:

   1. For each entry in subscriptions, run these steps:

      1. Let name be entry’s `name` member.

      2. Let url be the result of parsing entry’s `url` dictionary member with the context object's relevant settings object's API base URL.

      3. If url does not start with registration’s scope url, then reject p with a `TypeError` and abort these steps.

      4. Let matchType be entry’s `matchType` member.

      5. Let subscription be the cookie change subscription (name, url, matchType).

      6. Append subscription to registration’s associated cookie change subscription list.

   2. Resolve p with undefined.

6. Return p.

### 3.6. The `getChangeSubscriptions()` method

subscriptions = await cookieStore . `getChangeSubscriptions()`
  This method returns a promise which resolves to a list of the cookie change subscriptions made for this Service Worker registration.

The `getChangeSubscriptions()` method, when invoked, must run these steps:

1. Let serviceWorker be the context object's global object's service worker.

2. Let registration be serviceWorker’s associated containing service worker registration.

3. Let p be a new promise.

4. Run the following steps in parallel:

   1. Let subscriptions be registration’s associated cookie change subscription list.

   2. Let result be a new list.

   3. For each subscription in subscriptions, run these steps:

      1. Let options be a new `CookieStoreGetOptions` dictionary.

      2. Set options’s `name` member to subscription’s name.

      3. Set options’s `url` member to subscription’s url.

      4. Set options’s `matchType` member to subscription’s matchType.

   4. Resolve p with result.

5. Return p.

## 4. Event Interfaces

### 4.1. The `CookieChangeEvent` interface

A `CookieChangeEvent` is dispatched against `CookieStore` objects in `Window` contexts when any script-visible cookie changes have occurred.

    [Exposed=Window,
     SecureContext]
    interface CookieChangeEvent : Event {
      constructor(DOMString type, optional CookieChangeEventInit eventInitDict = {});
      readonly attribute CookieList changed;
      readonly attribute CookieList deleted;
    };

    dictionary CookieChangeEventInit : EventInit {
      CookieList changed;
      CookieList deleted;
    };

The `changed` and `deleted` attributes must return the value they were initialized to.

### 4.2. The `ExtendableCookieChangeEvent` interface

An `ExtendableCookieChangeEvent` is dispatched against `ServiceWorkerGlobalScope` objects when any script-visible cookie changes have occurred which match the Service Worker's cookie change subscription list.

    [Exposed=ServiceWorker
    ] interface ExtendableCookieChangeEvent : ExtendableEvent {
      constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict = {});
      readonly attribute CookieList changed;
      readonly attribute CookieList deleted;
    };

    dictionary ExtendableCookieChangeEventInit : ExtendableEventInit {
      CookieList changed;
      CookieList deleted;
    };

The `changed` and `deleted` attributes must return the value they were initialized to.

## 5. Global Interfaces

A `CookieStore` is accessed by script using an attribute in the global scope in a `Window` or `ServiceWorkerGlobalScope` context.

### 5.1. The `Window` interface

    [SecureContext]
    partial interface Window {
      [Replaceable, SameObject] readonly attribute CookieStore cookieStore;
    };

The `cookieStore` attribute’s getter must return context object's relevant settings object's `CookieStore` object.

### 5.2. The `ServiceWorkerGlobalScope` interface

    partial interface ServiceWorkerGlobalScope {
      [Replaceable, SameObject] readonly attribute CookieStore cookieStore;

      attribute EventHandler oncookiechange;
    };

The `cookieStore` attribute’s getter must return context object's relevant settings object's `CookieStore` object.

## 6. Algorithms

Cookie attribute-values are stored as byte sequences, not strings.

To encode a string, run UTF-8 encode on string.

To decode a value, run UTF-8 decode without BOM on value.

### 6.1. Query Cookies

To query cookies with url, optional name, and optional matchType, run the following steps:

1. Perform the steps defined in Cookies: HTTP State Management Mechanism §The Cookie Header to "compute the cookie-string from a cookie store" with url as request-uri. The cookie-string itself is ignored, but the intermediate cookie-list is used in subsequent steps.

   For the purposes of the steps, the cookie-string is being generated for a "non-HTTP" API.

2. Let list be a new list.

3. For each cookie in cookie-list, run these steps:

   1. Assert: cookie’s http-only-flag is false.

   2. If name is given, then run these steps:

      1. Let cookieName be cookie’s name (decoded).

      2. If cookieName does not match name using matchType, then continue.

   3. Let item be the result of running create a CookieListItem from cookie.

   4. Append item to list.

4. Return list.

A cookieName matches matchName using matchType if the following steps return true:

1. Switch on matchType:

   unspecified

     Return true.

   "`equals`"

     If cookieName does not equal matchName, then return false.

   "`starts-with`"

     If cookieName does not start with matchName, then return false.

2. Return true.

Note: If matchName is the empty string and matchType is "`starts-with`", then all cookieNames are matched.

To create a `CookieListItem` from cookie, run the following steps.

1. Let item be a new `CookieListItem`.

2. Set item’s `name` dictionary member to cookie’s name (decoded).

3. Set item’s `value` dictionary member to cookie’s value (decoded).

4. Set item’s `domain` dictionary member to cookie’s domain (decoded).

5. Set item’s `path` dictionary member to cookie’s path (decoded).

6. Set item’s `expires` dictionary member to cookie’s expiry-time (as a timestamp).

7. Set item’s `secure` dictionary member to cookie’s secure-only-flag.

8. Switch on cookie’s same-site-flag:

   ``None``

     Set item’s `sameSite` dictionary member to "`none`".

   ``Strict``

     Set item’s `sameSite` dictionary member to "`strict`".

   ``Lax``

     Set item’s `sameSite` dictionary member to "`lax`".

9. Return item.

Note: The cookie’s creation-time, last-access-time, persistent-flag, host-only-flag, and http-only-flag attributes are not exposed to script.

To represent a date and time dateTime as a timestamp, return the number of milliseconds from 00:00:00 UTC, 1 January 1970 to dateTime, (assuming that there are exactly 86,400,000 milliseconds per day).

Note: This is the same representation used for time values in [ECMAScript].

### 6.2. Set a Cookie

To set a cookie with url, name, value, optional expires, domain, path, secure flag, and sameSite, run the following steps:

1. If name’s length is 0 and value contains U+003D (`=`), then return failure.

2. Let host be url’s host

3. If domain is not null, then run these steps:

   1. If domain starts with U+002D (`.`), then return failure.

   2. If host does not equal domain and host does not end with U+002D (`.`) followed by domain, then return failure.

4. Otherwise, if domain is null, then set domain to host.

5. If secure is false and name starts with either "`__Secure-`" or "`__Host-`", then return failure.

6. Let attributes be a list.

7. If expires is given, then append ``Expires``/expires (date serialized) to attributes.

8. Append ``Domain``/domain (encoded) to attributes.

9. Append ``Path``/path (encoded) to attributes.

10. If secure is true, then append ``Secure``/`` to attributes.

11. Switch on sameSite:

    "`none`"

      Append ``SameSite``/``None`` to attributes.

    "`strict`"

      Append ``SameSite``/``Strict`` to attributes.

    "`lax`"

      Append ``SameSite``/``Lax`` to attributes.

12. Perform the steps defined in Cookies: HTTP State Management Mechanism §Storage Model for when the user agent "receives a cookie" with url as request-uri, name (encoded) as cookie-name, value (encoded) as cookie-value, and attributes as cookie-attribute-list.

    For the purposes of the steps, the newly-created cookie was received from a "non-HTTP" API.

13. Return success.

    Note: Storing the cookie may still fail due to requirements in [RFC6265bis] but these steps will be considered successful.

To date serialize a `DOMTimeStamp` millis, let dateTime be the date and time millis milliseconds after 00:00:00 UTC, 1 January 1970 (assuming that there are exactly 86,400,000 milliseconds per day), and return a byte sequence corresponding to the closest `cookie-date` representation of dateTime according to Cookies: HTTP State Management Mechanism §Dates.

### 6.3. Delete a Cookie

To delete a cookie with url, name, domain and path, run the following steps:

1. Let expires be the earliest representable date represented as a timestamp.

   Note: The exact value of expires is not important for the purposes of this algorithm, as long as it is in the past.

2. Let value be the empty string.

3. Let secure be true.

4. Let sameSite be "`strict`".

   Note: The values for value, secure, and sameSite will not be persisted by this algorithm.

5. Return the results of running set a cookie with url, name, value, expires, domain, path, secure, and sameSite.

### 6.4. Process Changes

To process cookie changes, run the following steps:

1. For every `Window` window, run the following steps:

   1. Let url be window’s creation URL.

   2. Let changes be the observable changes for url.

   3. If changes is empty, then continue.

   4. Queue a task to fire a change event named "`change`" with changes at window’s `CookieStore` on window’s responsible event loop.

2. For every service worker registration registration, run the following steps:

   1. Let changes be a new set.

   2. For each change in the observable changes for registration’s scope url, run these steps:

      1. Let cookie be change’s cookie.

      2. For each subscription in registration’s cookie change subscription list, run these steps:

         1. If change is not in the observable changes for subscription’s url, then continue.

         2. If cookie’s name (decoded) matches subscription’s name using subscription’s matchType, then append change to changes and break.

   3. If changes is empty, then continue.

   4. Let changedList and deletedList be the result of running prepare lists using changes for registration.

   5. Fire a functional event named "`cookiechange`" using `ExtendableCookieChangeEvent` on registration with these properties:

      `changed`

        changedList

      `deleted`

        deletedList

The observable changes for url are the set of cookie changes to cookies in a cookie store which meet the requirements in step 1 of Cookies: HTTP State Management Mechanism §The Cookie Header's steps to "compute the cookie-string from a cookie store" with url as request-uri, for a "non-HTTP" API.

A cookie change is a cookie and a type (either changed or deleted):

- A cookie which is removed due to an insertion of another cookie with the same name, domain, and path is ignored.

- A newly-created cookie which is not immediately evicted is considered changed.

- A newly-created cookie which is immediately evicted is considered deleted.

- A cookie which is otherwise evicted or removed is considered deleted

To fire a change event named type with changes at target, run the following steps:

1. Let event be the result of creating an Event using `CookieChangeEvent`.

2. Set event’s `type` attribute to type.

3. Set event’s `bubbles` and `cancelable` attributes to false.

4. Let changedList and deletedList be the result of running prepare lists using changes for target.

5. Set event’s `changed` attribute to changedList.

6. Set event’s `deleted` attribute to deletedList.

7. Dispatch event at target.

To prepare lists using changes for target, run the following steps:

1. Let changedList be a new list.

2. Let deletedList be a new list.

3. For each change in changes, run these steps:

   1. Let item be the result of running create a CookieListItem from change’s cookie.

   2. If change’s type is changed, then append item to changedList.

   3. Otherwise, run these steps:

      1. Set item’s `value` dictionary member to undefined.

      2. Append item to deletedList.

4. Return changedList and deletedList.

## 7. Security

Other than cookie access from service worker contexts, this API is not intended to expose any new capabilities to the web.

### 7.1. Gotcha!

Although browser cookie implementations are now evolving in the direction of better security and fewer surprising and error-prone defaults, there are at present few guarantees about cookie data security.

- unsecured origins can typically overwrite cookies used on secure origins

- superdomains can typically overwrite cookies seen by subdomains

- cross-site scripting attacts and other script and header injection attacks can be used to forge cookies too

- cookie read operations (both from script and on web servers) don’t give any indication of where the cookie came from

- browsers sometimes truncate, transform or evict cookie data in surprising and counterintuitive ways

  - ... due to reaching storage limits

  - ... due to character encoding differences

  - ... due to differing syntactic and semantic rules for cookies

For these reasons it is best to use caution when interpreting any cookie’s value, and never execute a cookie’s value as script, HTML, CSS, XML, PDF, or any other executable format.

### 7.2. Restrict?

This API may have the unintended side-effect of making cookies easier to use and consequently encouraging their further use. If it causes their further use in unsecured `http` contexts this could result in a web less safe for users. For that reason it may be desirable to restrict its use, or at least the use of the `set` and `delete` operations, to secure origins running in secure contexts.

### 7.3. Surprises

Some existing cookie behavior (especially domain-rather-than-origin orientation, unsecured contexts being able to set cookies readable in secure contexts, and script being able to set cookies unreadable from script contexts) may be quite surprising from a web security standpoint.

Other surprises are documented in Section 1 of Cookies: HTTP State Management Mechanism (RFC 6265bis) - for instance, a cookie may be set for a superdomain (e.g. app.example.com may set a cookie for the whole example.com domain), and a cookie may be readable across all port numbers on a given domain name.

Further complicating this are historical differences in cookie-handling across major browsers, although some of those (e.g. port number handling) are now handled with more consistency than they once were.

### 7.4. Prefixes

Where feasible the examples use the `__Host-` and `__Secure-` name prefixes which causes some current browsers to disallow overwriting from unsecured contexts, disallow overwriting with no `Secure` flag, and — in the case of `__Host-` — disallow overwriting with an explicit `Domain` or non-'/' `Path` attribute (effectively enforcing same-origin semantics.) These prefixes provide important security benefits in those browsers implementing Secure Cookies and degrade gracefully (i.e. the special semantics may not be enforced in other cookie APIs but the cookies work normally and the async cookies API enforces the secure semantics for write operations) in other browsers. A major goal of this API is interoperation with existing cookies, though, so a few examples have also been provided using cookie names lacking these prefixes.

Prefix rules are also enforced in write operations by this API, but may not be enforced in the same browser for other APIs. For this reason it is inadvisable to rely on their enforcement too heavily until and unless they are more broadly adopted.

### 7.5. URL scoping

Although a service worker script cannot directly access cookies today, it can already use controlled rendering of in-scope HTML and script resources to inject cookie-monitoring code under the remote control of the service worker script. This means that cookie access inside the scope of the service worker is technically possible already, it’s just not very convenient.

When the service worker is scoped more narrowly than `/` it may still be able to read path-scoped cookies from outside its scope’s path space by successfully guessing/constructing a 404 page URL which allows IFRAME-ing and then running script inside it the same technique could expand to the whole origin, but a carefully constructed site (one where no out-of-scope pages are IFRAME-able) can actually deny this capability to a path-scoped service worker today and I was reluctant to remove that restriction without further discussion of the implications.

### 7.6. Cookie aversion

To reduce complexity for developers and eliminate the need for ephemeral test cookies, this async cookies API will explicitly reject attempts to write or delete cookies when the operation would be ignored. Likewise it will explicitly reject attempts to read cookies when that operation would ignore actual cookie data and simulate an empty cookie jar. Attempts to observe cookie changes in these contexts will still "work", but won’t invoke the callback until and unless read access becomes allowed (due e.g. to changed site permissions.)

Today writing to `document.cookie` in contexts where script-initiated cookie-writing is disallowed typically is a no-op. However, many cookie-writing scripts and frameworks always write a test cookie and then check for its existence to determine whether script-initiated cookie-writing is possible.

Likewise, today reading `document.cookie` in contexts where script-initiated cookie-reading is disallowed typically returns an empty string. However, a cooperating web server can verify that server-initiated cookie-writing and cookie-reading work and report this to the script (which still sees empty string) and the script can use this information to infer that script-initiated cookie-reading is disallowed.

## 8. Acknowledgements

Thanks to Benjamin Sittler, who created the initial proposal for this API.

Many thanks to Adam Barth, Alex Russell, Andrea Marchesini, Anne van Kesteren, Ben Kelly, Craig Francis, Daniel Murphy, Domenic Denicola, Elliott Sprehn, Fagner Brack, Jake Archibald, Joel Weinberger, Marijn Kruisselbrink, and Mike West for helping craft this proposal.

Special thanks to Tab Atkins, Jr. for creating and maintaining Bikeshed, the specification authoring tool used to create this document, and for his general authoring advice.

## Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with `class="example"`, like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with `class="note"`, like this:

Note, this is an informative note.

## Index

### Terms defined by this specification

- as a timestamp, in §6.1
- changed
  - attribute for CookieChangeEvent, in §4.1
  - attribute for ExtendableCookieChangeEvent, in §4.2
  - dict-member for CookieChangeEventInit, in §4.1
  - dict-member for ExtendableCookieChangeEventInit, in §4.2
- constructor(type)
  - constructor for CookieChangeEvent, in §4.1
  - constructor for ExtendableCookieChangeEvent, in §4.2
- constructor(type, eventInitDict)
  - constructor for CookieChangeEvent, in §4.1
  - constructor for ExtendableCookieChangeEvent, in §4.2
- cookie, in §2.1
- cookie change, in §6.4
- CookieChangeEvent, in §4.1
- CookieChangeEventInit, in §4.1
- CookieChangeEvent(type), in §4.1
- CookieChangeEvent(type, eventInitDict), in §4.1
- cookie change subscription, in §2.3
- cookie change subscription list, in §2.3
- CookieList, in §3
- CookieListItem, in §3
- CookieMatchType, in §3
- CookieSameSite, in §3
- cookie store, in §2.2
- CookieStore, in §3
- cookieStore
  - attribute for ServiceWorkerGlobalScope, in §5.2
  - attribute for Window, in §5.1
- CookieStoreDeleteOptions, in §3
- CookieStoreGetOptions, in §3
- CookieStoreSetExtraOptions, in §3
- CookieStoreSetOptions, in §3
- create a CookieListItem, in §6.1
- creation-time, in §2.1
- date serialize, in §6.2
- decode, in §6
- delete a cookie, in §6.3
- deleted
  - attribute for CookieChangeEvent, in §4.1
  - attribute for ExtendableCookieChangeEvent, in §4.2
  - dict-member for CookieChangeEventInit, in §4.1
  - dict-member for ExtendableCookieChangeEventInit, in §4.2
- delete(name), in §3.4
- delete(options), in §3.4
- domain
  - dfn for cookie, in §2.1
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreDeleteOptions, in §3
  - dict-member for CookieStoreSetOptions, in §3
- encode, in §6
- "equals", in §3
- expires
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreSetOptions, in §3
- expiry-time, in §2.1
- ExtendableCookieChangeEvent, in §4.2
- ExtendableCookieChangeEventInit, in §4.2
- ExtendableCookieChangeEvent(type), in §4.2
- ExtendableCookieChangeEvent(type, eventInitDict), in §4.2
- fire a change event, in §6.4
- get(), in §3.1
- getAll(), in §3.2
- getAll(name), in §3.2
- getAll(options), in §3.2
- getChangeSubscriptions(), in §3.6
- get(name), in §3.1
- get(options), in §3.1
- host-only-flag, in §2.1
- http-only-flag, in §2.1
- last-access-time, in §2.1
- "lax", in §3
- matches, in §6.1
- matchType
  - dfn for cookie change subscription, in §2.3
  - dict-member for CookieStoreGetOptions, in §3
- name
  - dfn for cookie, in §2.1
  - dfn for cookie change subscription, in §2.3
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreDeleteOptions, in §3
  - dict-member for CookieStoreGetOptions, in §3
  - dict-member for CookieStoreSetExtraOptions, in §3
- "none", in §3
- observable changes, in §6.4
- onchange, in §3
- oncookiechange, in §5.2
- path
  - dfn for cookie, in §2.1
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreDeleteOptions, in §3
  - dict-member for CookieStoreSetOptions, in §3
- persistent-flag, in §2.1
- prepare lists, in §6.4
- process cookie changes, in §6.4
- query cookies, in §6.1
- sameSite
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreSetOptions, in §3
- same-site-flag, in §2.1
- script-visible, in §1.2.1
- secure
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreSetOptions, in §3
- secure-only-flag, in §2.1
- set a cookie, in §6.2
- set(name, value), in §3.3
- set(name, value, options), in §3.3
- set(options), in §3.3
- "starts-with", in §3
- "strict", in §3
- subscribeToChanges(subscriptions), in §3.5
- url
  - dfn for cookie change subscription, in §2.3
  - dict-member for CookieStoreGetOptions, in §3
- value
  - dfn for cookie, in §2.1
  - dict-member for CookieListItem, in §3
  - dict-member for CookieStoreSetExtraOptions, in §3

https://dom.spec.whatwg.org/#event Referenced in:

- 4.1. The CookieChangeEvent interface

https://dom.spec.whatwg.org/#dictdef-eventinit Referenced in:

- 4.1. The CookieChangeEvent interface

https://dom.spec.whatwg.org/#eventtarget Referenced in:

- 3. The CookieStore Interface

https://dom.spec.whatwg.org/#dom-event-bubbles Referenced in:

- 6.4. Process Changes

https://dom.spec.whatwg.org/#dom-event-cancelable Referenced in:

- 6.4. Process Changes

https://dom.spec.whatwg.org/#context-object Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 3.5. The subscribeToChanges() method (2)
- 3.6. The getChangeSubscriptions() method
- 5.1. The Window interface
- 5.2. The ServiceWorkerGlobalScope interface

https://dom.spec.whatwg.org/#concept-event-create Referenced in:

- 6.4. Process Changes

https://dom.spec.whatwg.org/#concept-event-dispatch Referenced in:

- 4.1. The CookieChangeEvent interface
- 4.2. The ExtendableCookieChangeEvent interface
- 6.4. Process Changes

https://dom.spec.whatwg.org/#concept-document Referenced in:

- 1.3. Querying Cookies (2) (3)
- 1.4. Modifying Cookies
- 1.5. Monitoring Cookies

https://dom.spec.whatwg.org/#dom-event-type Referenced in:

- 6.4. Process Changes

https://tc39.github.io/ecma262/#sec-promise-objects Referenced in:

- 1.3. Querying Cookies

https://tc39.github.io/ecma262/#sec-time-values-and-time-range Referenced in:

- 6.1. Query Cookies

https://encoding.spec.whatwg.org/#utf-8-decode-without-bom Referenced in:

- 6. Algorithms

https://encoding.spec.whatwg.org/#utf-8-encode Referenced in:

- 6. Algorithms

https://fetch.spec.whatwg.org/#concept-fetch Referenced in:

- 1.3. Querying Cookies

https://fetch.spec.whatwg.org/#concept-request-window Referenced in:

- 1.5. Monitoring Cookies

https://html.spec.whatwg.org/multipage/webappapis.html#eventhandler Referenced in:

- 3. The CookieStore Interface
- 5.2. The ServiceWorkerGlobalScope interface

https://html.spec.whatwg.org/multipage/window-object.html#window Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 4.1. The CookieChangeEvent interface
- 5. Global Interfaces
- 5.1. The Window interface (2)
- 6.4. Process Changes

https://html.spec.whatwg.org/multipage/webappapis.html#api-base-url Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 3.5. The subscribeToChanges() method

https://html.spec.whatwg.org/multipage/dom.html#dom-document-cookie Referenced in:

- 1. Introduction (2)
- 1.2.2. Motivations
- 1.2.4. Compatiblity (2) (3)
- 1.3. Querying Cookies
- 7.6. Cookie aversion (2)

https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-creation-url Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)
- 6.4. Process Changes

https://html.spec.whatwg.org/multipage/webappapis.html#current-global-object Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method

https://html.spec.whatwg.org/multipage/webappapis.html#current-settings-object Referenced in:

- 3.1. The get() method (2) (3) (4)
- 3.2. The getAll() method (2) (3) (4)
- 3.3. The set() method (2) (3) (4)
- 3.4. The delete() method (2) (3) (4)

https://html.spec.whatwg.org/multipage/origin.html#dom-document-domain Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method

https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-global Referenced in:

- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)
- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)

https://html.spec.whatwg.org/multipage/origin.html#concept-origin Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)

https://html.spec.whatwg.org/multipage/webappapis.html#queue-a-task Referenced in:

- 6.4. Process Changes

https://html.spec.whatwg.org/multipage/webappapis.html#relevant-settings-object Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 3.5. The subscribeToChanges() method
- 5.1. The Window interface
- 5.2. The ServiceWorkerGlobalScope interface

https://html.spec.whatwg.org/multipage/history.html#dom-history-replacestate Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method

https://html.spec.whatwg.org/multipage/webappapis.html#responsible-event-loop Referenced in:

- 6.4. Process Changes

https://html.spec.whatwg.org/multipage/origin.html#same-origin Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method

https://infra.spec.whatwg.org/#set-append Referenced in:

- 6.4. Process Changes

https://infra.spec.whatwg.org/#iteration-break Referenced in:

- 6.4. Process Changes

https://infra.spec.whatwg.org/#byte-sequence Referenced in:

- 6. Algorithms
- 6.2. Set a Cookie

https://infra.spec.whatwg.org/#code-point Referenced in:

- 1.2.3. Opinions (2)

https://infra.spec.whatwg.org/#list-contain Referenced in:

- 6.4. Process Changes

https://infra.spec.whatwg.org/#iteration-continue Referenced in:

- 6.1. Query Cookies
- 6.4. Process Changes (2) (3)

https://infra.spec.whatwg.org/#list-iterate Referenced in:

- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method
- 6.1. Query Cookies
- 6.4. Process Changes (2) (3)

https://infra.spec.whatwg.org/#list-is-empty Referenced in:

- 3.1. The get() method (2)
- 6.4. Process Changes (2)

https://infra.spec.whatwg.org/#string-length Referenced in:

- 6.2. Set a Cookie

https://infra.spec.whatwg.org/#list Referenced in:

- 2.3. Extensions to Service Worker
- 3.6. The getChangeSubscriptions() method
- 6.1. Query Cookies
- 6.2. Set a Cookie
- 6.4. Process Changes (2)

https://infra.spec.whatwg.org/#ordered-set Referenced in:

- 6.4. Process Changes (2)

https://infra.spec.whatwg.org/#tuple Referenced in:

- 2.3. Extensions to Service Worker

https://www.w3.org/2001/tag/doc/promises-guide/#a-new-promise Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)
- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

https://www.w3.org/2001/tag/doc/promises-guide/#a-promise-rejected-with Referenced in:

- 3.1. The get() method (2) (3) (4)
- 3.2. The getAll() method (2) (3) (4)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)
- 3.5. The subscribeToChanges() method

https://www.w3.org/2001/tag/doc/promises-guide/#reject-promise Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)
- 3.5. The subscribeToChanges() method

https://w3c.github.io/ServiceWorker/#extendableevent Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface

https://w3c.github.io/ServiceWorker/#dictdef-extendableeventinit Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface

https://w3c.github.io/ServiceWorker/#serviceworkerglobalscope Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface
- 5. Global Interfaces
- 5.2. The ServiceWorkerGlobalScope interface (2)

https://w3c.github.io/ServiceWorker/#dfn-containing-service-worker-registration Referenced in:

- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

https://w3c.github.io/ServiceWorker/#fire-functional-event Referenced in:

- 6.4. Process Changes

https://w3c.github.io/ServiceWorker/#dfn-scope-url Referenced in:

- 1.3. Querying Cookies
- 3.5. The subscribeToChanges() method
- 6.4. Process Changes

https://w3c.github.io/ServiceWorker/#dfn-service-worker Referenced in:

- 1.3. Querying Cookies (2) (3)
- 1.4. Modifying Cookies
- 1.5. Monitoring Cookies (2) (3) (4) (5)
- 3.5. The subscribeToChanges() method (2) (3)
- 3.6. The getChangeSubscriptions() method
- 4.2. The ExtendableCookieChangeEvent interface

https://w3c.github.io/ServiceWorker/#dfn-service-worker-registration Referenced in:

- 1.5. Monitoring Cookies
- 2.3. Extensions to Service Worker (2)
- 6.4. Process Changes

https://w3c.github.io/ServiceWorker/#dfn-state Referenced in:

- 1.5. Monitoring Cookies (2)
- 3.5. The subscribeToChanges() method

https://url.spec.whatwg.org/#concept-basic-url-parser Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 3.5. The subscribeToChanges() method

https://url.spec.whatwg.org/#concept-url-equals Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method

https://url.spec.whatwg.org/#concept-url-host Referenced in:

- 6.2. Set a Cookie

https://url.spec.whatwg.org/#concept-url-origin Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)

https://heycam.github.io/webidl/#idl-DOMException Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)

https://heycam.github.io/webidl/#idl-DOMString Referenced in:

- 4.1. The CookieChangeEvent interface
- 4.2. The ExtendableCookieChangeEvent interface

https://heycam.github.io/webidl/#DOMTimeStamp Referenced in:

- 3. The CookieStore Interface (2)
- 6.2. Set a Cookie

https://heycam.github.io/webidl/#Exposed Referenced in:

- 3. The CookieStore Interface (2) (3) (4)
- 4.1. The CookieChangeEvent interface
- 4.2. The ExtendableCookieChangeEvent interface

https://heycam.github.io/webidl/#Replaceable Referenced in:

- 5.1. The Window interface
- 5.2. The ServiceWorkerGlobalScope interface

https://heycam.github.io/webidl/#SameObject Referenced in:

- 5.1. The Window interface
- 5.2. The ServiceWorkerGlobalScope interface

https://heycam.github.io/webidl/#SecureContext Referenced in:

- 3. The CookieStore Interface
- 4.1. The CookieChangeEvent interface
- 5.1. The Window interface

https://heycam.github.io/webidl/#securityerror Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)

https://heycam.github.io/webidl/#exceptiondef-typeerror Referenced in:

- 3.1. The get() method (2) (3) (4)
- 3.2. The getAll() method (2) (3) (4)
- 3.3. The set() method (2)
- 3.4. The delete() method (2)
- 3.5. The subscribeToChanges() method (2)

https://heycam.github.io/webidl/#idl-USVString Referenced in:

- 1.2.4. Compatiblity
- 3. The CookieStore Interface (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18)

https://heycam.github.io/webidl/#idl-boolean Referenced in:

- 3. The CookieStore Interface (2)

### Terms defined by reference

- [DOM] defines the following terms:
  - Event
  - EventInit
  - EventTarget
  - bubbles
  - cancelable
  - context object
  - creating an event
  - dispatch
  - document
  - type
- [ecma262] defines the following terms:
  - promise
  - time values
- [ENCODING] defines the following terms:
  - utf-8 decode without bom
  - utf-8 encode
- [FETCH] defines the following terms:
  - fetch
  - window
- [HTML] defines the following terms:
  - EventHandler
  - Window
  - api base url
  - cookie
  - creation url
  - current global object
  - current settings object
  - domain
  - global object
  - in parallel
  - opaque origin
  - origin
  - queue a task
  - relevant settings object
  - replaceState(data, title)
  - responsible event loop
  - same origin
- [INFRA] defines the following terms:
  - append (for set)
  - break
  - byte sequence
  - code point
  - contain
  - continue
  - for each
  - is empty
  - length
  - list
  - set
  - tuple
- [promises-guide] defines the following terms:
  - a new promise
  - a promise rejected with
  - reject
- [Service-Workers] defines the following terms:
  - ExtendableEvent
  - ExtendableEventInit
  - ServiceWorkerGlobalScope
  - containing service worker registration
  - fire a functional event
  - scope url
  - service worker
  - service worker registration
  - state
- [URL] defines the following terms:
  - basic url parser
  - equal
  - host
  - origin
- [WebIDL] defines the following terms:
  - DOMException
  - DOMString
  - DOMTimeStamp
  - Exposed
  - Replaceable
  - SameObject
  - SecureContext
  - SecurityError
  - TypeError
  - USVString
  - boolean

## References

### Normative References

[DOM]
  Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ENCODING]
  Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/
[FETCH]
  Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
  Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
  Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PROMISES-GUIDE]
  Domenic Denicola. Writing Promise-Using Specifications. 9 November 2018. TAG Finding. URL: https://www.w3.org/2001/tag/doc/promises-guide
[RFC2119]
  S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[RFC6265bis]
  A. Barth; M. West. Cookies: HTTP State Management Mechanism. Internet-Draft. URL: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03
[Service-Workers]
  Alex Russell; et al. Service Workers 1. 2 November 2017. WD. URL: https://www.w3.org/TR/service-workers-1/
[URL]
  Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WebIDL]
  Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

### Informative References

[ECMAScript]
  ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/

## IDL Index

    [Exposed=(ServiceWorker,Window),
     SecureContext]
    interface CookieStore : EventTarget {
      Promise<CookieListItem?> get(USVString name);
      Promise<CookieListItem?> get(optional CookieStoreGetOptions options = {});

      Promise<CookieList> getAll(USVString name);
      Promise<CookieList> getAll(optional CookieStoreGetOptions options = {});

      Promise<void> set(USVString name, USVString value,
                        optional CookieStoreSetOptions options = {});
      Promise<void> set(CookieStoreSetExtraOptions options);

      Promise<void> delete(USVString name);
      Promise<void> delete(CookieStoreDeleteOptions options);

      [Exposed=ServiceWorker]
      Promise<void> subscribeToChanges(sequence<CookieStoreGetOptions> subscriptions);

      [Exposed=ServiceWorker]
      Promise<sequence<CookieStoreGetOptions>> getChangeSubscriptions();

      [Exposed=Window]
      attribute EventHandler onchange;
    };

    enum CookieMatchType {
      "equals",
      "starts-with"
    };

    dictionary CookieStoreGetOptions {
      USVString name;
      USVString url;
      CookieMatchType matchType = "equals";
    };

    enum CookieSameSite {
      "strict",
      "lax",
      "none"
    };

    dictionary CookieStoreSetOptions {
      DOMTimeStamp? expires = null;
      USVString? domain = null;
      USVString path = "/";
      boolean secure = true;
      CookieSameSite sameSite = "strict";
    };

    dictionary CookieStoreSetExtraOptions : CookieStoreSetOptions {
      required USVString name;
      required USVString value;
    };

    dictionary CookieStoreDeleteOptions {
      required USVString name;
      USVString? domain = null;
      USVString path = "/";
    };

    dictionary CookieListItem {
      required USVString name;
      USVString value;
      USVString? domain = null;
      USVString path = "/";
      DOMTimeStamp? expires = null;
      boolean secure = true;
      CookieSameSite sameSite = "strict";
    };

    typedef sequence<CookieListItem> CookieList;

    [Exposed=Window,
     SecureContext]
    interface CookieChangeEvent : Event {
      constructor(DOMString type, optional CookieChangeEventInit eventInitDict = {});
      readonly attribute CookieList changed;
      readonly attribute CookieList deleted;
    };

    dictionary CookieChangeEventInit : EventInit {
      CookieList changed;
      CookieList deleted;
    };

    [Exposed=ServiceWorker
    ] interface ExtendableCookieChangeEvent : ExtendableEvent {
      constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict = {});
      readonly attribute CookieList changed;
      readonly attribute CookieList deleted;
    };

    dictionary ExtendableCookieChangeEventInit : ExtendableEventInit {
      CookieList changed;
      CookieList deleted;
    };

    [SecureContext]
    partial interface Window {
      [Replaceable, SameObject] readonly attribute CookieStore cookieStore;
    };

    partial interface ServiceWorkerGlobalScope {
      [Replaceable, SameObject] readonly attribute CookieStore cookieStore;

      attribute EventHandler oncookiechange;
    };

## Issues Index

How about when "the current session is over" for non-persistent cookies? ↵
#script-visible Referenced in:

- 1.2. Summary (2)
- 3.1. The get() method
- 3.2. The getAll() method
- 4.1. The CookieChangeEvent interface
- 4.2. The ExtendableCookieChangeEvent interface

#cookie Referenced in:

- 2.1. Cookie
- 2.2. Cookie Store (2) (3)
- 6. Algorithms
- 6.4. Process Changes (2) (3) (4) (5) (6) (7)

#cookie-name Referenced in:

- 1.3. Querying Cookies
- 6.1. Query Cookies (2)
- 6.4. Process Changes (2)

#cookie-value Referenced in:

- 1.3. Querying Cookies
- 6.1. Query Cookies

#cookie-expiry-time Referenced in:

- 6.1. Query Cookies

#cookie-domain Referenced in:

- 6.1. Query Cookies
- 6.4. Process Changes

#cookie-path Referenced in:

- 6.1. Query Cookies
- 6.4. Process Changes

#cookie-creation-time Referenced in:

- 6.1. Query Cookies

#cookie-last-access-time Referenced in:

- 6.1. Query Cookies

#cookie-persistent-flag Referenced in:

- 6.1. Query Cookies

#cookie-host-only-flag Referenced in:

- 6.1. Query Cookies

#cookie-secure-only-flag Referenced in:

- 6.1. Query Cookies

#cookie-http-only-flag Referenced in:

- 6.1. Query Cookies (2)

#cookie-same-site-flag Referenced in:

- 6.1. Query Cookies

#cookie-store Referenced in:

- 2.2. Cookie Store (2) (3) (4)
- 6.4. Process Changes

#cookie-change-subscription-list Referenced in:

- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method
- 4.2. The ExtendableCookieChangeEvent interface
- 6.4. Process Changes

#cookie-change-subscription Referenced in:

- 2.3. Extensions to Service Worker
- 3.5. The subscribeToChanges() method

#cookie-change-subscription-name Referenced in:

- 3.6. The getChangeSubscriptions() method
- 6.4. Process Changes

#cookie-change-subscription-url Referenced in:

- 3.6. The getChangeSubscriptions() method
- 6.4. Process Changes

#cookie-change-subscription-matchtype Referenced in:

- 3.6. The getChangeSubscriptions() method
- 6.4. Process Changes

#cookiestore Referenced in:

- 1.3. Querying Cookies
- 3. The CookieStore Interface
- 4.1. The CookieChangeEvent interface
- 5. Global Interfaces
- 5.1. The Window interface (2)
- 5.2. The ServiceWorkerGlobalScope interface (2)
- 6.4. Process Changes

#enumdef-cookiematchtype Referenced in:

- 3. The CookieStore Interface

#dom-cookiematchtype-equals Referenced in:

- 6.1. Query Cookies

#dom-cookiematchtype-starts-with Referenced in:

- 6.1. Query Cookies (2)

#dictdef-cookiestoregetoptions Referenced in:

- 3. The CookieStore Interface (2) (3) (4)
- 3.6. The getChangeSubscriptions() method

#dom-cookiestoregetoptions-name Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

#dom-cookiestoregetoptions-url Referenced in:

- 1.3. Querying Cookies
- 3.1. The get() method (2)
- 3.2. The getAll() method (2)
- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

#dom-cookiestoregetoptions-matchtype Referenced in:

- 3.1. The get() method
- 3.2. The getAll() method
- 3.5. The subscribeToChanges() method
- 3.6. The getChangeSubscriptions() method

#enumdef-cookiesamesite Referenced in:

- 3. The CookieStore Interface (2)

#dom-cookiesamesite-strict Referenced in:

- 3.4. The delete() method
- 6.1. Query Cookies
- 6.2. Set a Cookie
- 6.3. Delete a Cookie

#dom-cookiesamesite-lax Referenced in:

- 6.1. Query Cookies
- 6.2. Set a Cookie

#dom-cookiesamesite-none Referenced in:

- 6.1. Query Cookies
- 6.2. Set a Cookie

#dictdef-cookiestoresetoptions Referenced in:

- 3. The CookieStore Interface (2)

#dom-cookiestoresetoptions-expires Referenced in:

- 3.3. The set() method (2)

#dom-cookiestoresetoptions-domain Referenced in:

- 3.3. The set() method (2)

#dom-cookiestoresetoptions-path Referenced in:

- 3.3. The set() method (2)

#dom-cookiestoresetoptions-secure Referenced in:

- 3.3. The set() method (2)

#dom-cookiestoresetoptions-samesite Referenced in:

- 3.3. The set() method (2)

#dictdef-cookiestoresetextraoptions Referenced in:

- 3. The CookieStore Interface

#dom-cookiestoresetextraoptions-name Referenced in:

- 3.3. The set() method

#dom-cookiestoresetextraoptions-value Referenced in:

- 3.3. The set() method

#dictdef-cookiestoredeleteoptions Referenced in:

- 3. The CookieStore Interface

#dom-cookiestoredeleteoptions-name Referenced in:

- 3.4. The delete() method

#dom-cookiestoredeleteoptions-domain Referenced in:

- 3.4. The delete() method

#dom-cookiestoredeleteoptions-path Referenced in:

- 3.4. The delete() method

#dictdef-cookielistitem Referenced in:

- 3. The CookieStore Interface (2) (3)
- 6.1. Query Cookies (2)

#dom-cookielistitem-name Referenced in:

- 6.1. Query Cookies

#dom-cookielistitem-value Referenced in:

- 6.1. Query Cookies
- 6.4. Process Changes

#dom-cookielistitem-domain Referenced in:

- 6.1. Query Cookies

#dom-cookielistitem-path Referenced in:

- 6.1. Query Cookies

#dom-cookielistitem-expires Referenced in:

- 6.1. Query Cookies

#dom-cookielistitem-secure Referenced in:

- 6.1. Query Cookies

#dom-cookielistitem-samesite Referenced in:

- 6.1. Query Cookies (2) (3)

#typedefdef-cookielist Referenced in:

- 3. The CookieStore Interface (2)
- 4.1. The CookieChangeEvent interface (2) (3) (4)
- 4.2. The ExtendableCookieChangeEvent interface (2) (3) (4)

#dom-cookiestore-get Referenced in:

- 3. The CookieStore Interface
- 3.1. The get() method

#dom-cookiestore-get-options Referenced in:

- 1.3. Querying Cookies (2) (3)
- 1.5. Monitoring Cookies
- 3. The CookieStore Interface
- 3.1. The get() method (2)

#dom-cookiestore-getall Referenced in:

- 3. The CookieStore Interface
- 3.2. The getAll() method

#dom-cookiestore-getall-options Referenced in:

- 1.3. Querying Cookies (2) (3)
- 1.5. Monitoring Cookies
- 3. The CookieStore Interface
- 3.2. The getAll() method (2)

#dom-cookiestore-set Referenced in:

- 1.4. Modifying Cookies (2)
- 3. The CookieStore Interface
- 3.3. The set() method (2)

#dom-cookiestore-set-options Referenced in:

- 3. The CookieStore Interface
- 3.3. The set() method

#dom-cookiestore-delete Referenced in:

- 1.4. Modifying Cookies
- 3. The CookieStore Interface
- 3.4. The delete() method (2)

#dom-cookiestore-delete-options Referenced in:

- 3. The CookieStore Interface
- 3.4. The delete() method

#dom-cookiestore-subscribetochanges Referenced in:

- 1.5. Monitoring Cookies
- 3. The CookieStore Interface
- 3.5. The subscribeToChanges() method (2)

#dom-cookiestore-getchangesubscriptions Referenced in:

- 1.5. Monitoring Cookies
- 3. The CookieStore Interface
- 3.6. The getChangeSubscriptions() method (2)

#cookiechangeevent Referenced in:

- 4.1. The CookieChangeEvent interface (2)
- 6.4. Process Changes

#dom-cookiechangeevent-changed Referenced in:

- 4.1. The CookieChangeEvent interface
- 6.4. Process Changes

#dom-cookiechangeevent-deleted Referenced in:

- 4.1. The CookieChangeEvent interface
- 6.4. Process Changes

#dictdef-cookiechangeeventinit Referenced in:

- 4.1. The CookieChangeEvent interface

#extendablecookiechangeevent Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface (2)
- 6.4. Process Changes

#dom-extendablecookiechangeevent-changed Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface
- 6.4. Process Changes

#dom-extendablecookiechangeevent-deleted Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface
- 6.4. Process Changes

#dictdef-extendablecookiechangeeventinit Referenced in:

- 4.2. The ExtendableCookieChangeEvent interface

#dom-window-cookiestore Referenced in:

- 1.3. Querying Cookies
- 1.4. Modifying Cookies
- 5.1. The Window interface

#dom-serviceworkerglobalscope-cookiestore Referenced in:

- 5.2. The ServiceWorkerGlobalScope interface

#encode Referenced in:

- 6.2. Set a Cookie (2) (3) (4)

#decode Referenced in:

- 6.1. Query Cookies (2) (3) (4) (5)
- 6.4. Process Changes

#query-cookies Referenced in:

- 3.1. The get() method (2)
- 3.2. The getAll() method (2)

#matches Referenced in:

- 6.1. Query Cookies
- 6.4. Process Changes

#create-a-cookielistitem Referenced in:

- 6.1. Query Cookies
- 6.4. Process Changes

#as-a-timestamp Referenced in:

- 6.1. Query Cookies
- 6.3. Delete a Cookie

#set-a-cookie Referenced in:

- 3.3. The set() method (2)
- 6.3. Delete a Cookie

#date-serialize Referenced in:

- 6.2. Set a Cookie

#delete-a-cookie Referenced in:

- 3.4. The delete() method (2)

#process-cookie-changes Referenced in:

- 2.2. Cookie Store

#observable-changes Referenced in:

- 6.4. Process Changes (2) (3)

#cookie-change Referenced in:

- 6.4. Process Changes

#fire-a-change-event Referenced in:

- 6.4. Process Changes

#prepare-lists Referenced in:

- 6.4. Process Changes (2)