Using the Storage Access API

The Storage Access API should be used by embedded cross-origin documents to verify whether they have access to their first-party storage and, if not, to request access. We'll briefly look at a common storage access scenario.

Usage notes

The Storage Access API is designed to allow embedded content to request access to storage that would otherwise be blocked when a user's browser is set to block all third-party cookies. Since embedded content won't know which storage policy is in use by the user, it's best to always check whether the embedded frame has storage access before attempting to read or write from storage. This is particularly true for Document.cookie access, as browsers will often return an empty cookie jar when third-party cookies are blocked.

Accessing a user's cookies in an embedded cross-origin iframe

In this example we show how an embedded cross-origin <iframe> can access a user's cookies under a storage access policy that blocks third-party cookies.

First of all, if the <iframe> is sandboxed, the embedding website needs to add the allow-storage-access-by-user-activation sandbox token to allow storage access requests to be successful, along with allow-scripts and allow-same-origin to allow it to call the API, and execute in an origin that can have cookies:

<iframe
  sandbox="allow-storage-access-by-user-activation
                 allow-scripts
                 allow-same-origin"></iframe>

Now on to the code executed inside the embedded document. Since it does not know whether it currently has access to storage, it should first call Document.hasStorageAccess(). If that call returns false, we can then call Document.requestStorageAccess(), returning the result so that then we can chain it onto the previous promise call. In the final then, we'll have first-party storage access.

function doThingsWithFirstPartyStorageAccess() {
  // Let's access some items from the first-party cookie jar
  document.cookie = "foo=bar"; // set a cookie
  localStorage.setItem("username", "John"); // access a localStorage entry
}

if (document.hasStorageAccess == null) {
  // This browser doesn't support the Storage Access API, so let's just hope we have access!
  doThingsWithFirstPartyStorageAccess();
} else {
  document.hasStorageAccess().then((hasAccess) => {
    if (hasAccess) {
      // We already have access, so let's do things right away!
      doThingsWithFirstPartyStorageAccess();
    } else {
      // As we don't have access, we need to request it. This request has to happen within
      // an event handler for a user interaction (e.g., clicking)
      btn.addEventListener("click", () => {
        document
          .requestStorageAccess()
          .then(() => {
            doThingsWithFirstPartyStorageAccess();
          })
          .catch((err) => {
            // If there is an error obtaining storage access.
            console.error("Error obtaining storage access", err);
          });
      });
    }
  });
}

Note that access requests are automatically denied unless the embedded content is currently processing a user gesture such as a tap or click — so this code needs to be run inside some kind of user gesture-based event handler, for example:

btn.addEventListener("click", () => {
  // run code here
});