Introducing Storage Access API

Note: Read about improvements to this technology with Intelligent Tracking Prevention 2.0.

In June last year we introduced Intelligent Tracking Prevention (ITP). ITP is a privacy feature that detects which domains have the ability to track the user cross-site and either partitions the domain’s cookies or purges its website data all together.

The strongest developer feedback we got on ITP was that it needs to provide a way for embedded cross-site content to authenticate users who are already logged in to their first-party services. Today we are happy to provide a solution in the form of Storage Access API. It allows for authenticated embeds while continuing to protect customers’ privacy by default.

Partitioned Cookies and Embedded Content

Let’s say that socialexample.org is embedded on multiple websites to facilitate commenting or “liking” content with the user’s socialexample ID. ITP will detect that such multi-page embeds gives socialexample.org the ability to track the user cross-site and therefore deny embedded content from socialexample.org access to its first-party cookies, providing only partitioned cookies. This breaks the user’s ability to comment and like content unless they have interacted with socialexample.org as first-party site in the last 24 hours. (Please see the original ITP blog post for the exact rules around partitioned cookies.)

The same goes for embedded third-party payment providers and embedded third-party videos from subscription services. As soon as ITP detects their tracking abilities, it denies them first-party cookie access outside the 24 hour window, and the embedded content treats the user as logged out even though they are logged in.

We’ve made tradeoffs for user privacy. But it would be even better if we could provide the benefits of being logged in to third party iframes, provided that the user is actually interested in using them, while still protecting privacy.

The Solution: Storage Access API

The solution is to allow third-party embeds to request access to their first-party cookies when the user interacts with them. To do this, we created the Storage Access API.

The Storage Access API offers two new functions to cross-origin iframes — document.hasStorageAccess() and document.requestStorageAccess(). It also offers the embedding top frame a new iframe sandbox token — “allow-storage-access-by-user-activation”.

Storage access in this context means that the iframe has access to its first-party cookies, i.e. the same cookies it would have access to as a first-party site. Note that storage access does not relax the same-origin policy in any way. Specifically, this is not about third-party iframes getting access to the embedding website’s cookies and storage, or vice versa.

WebKit’s implementation of the API only covers cookies for now. It does not affect the partitioning of other storage forms such as IndexedDB or LocalStorage.

Check For Storage Access

A call to document.hasStorageAccess() returns a promise that resolves with a boolean indicating whether the document already has access to its first-party cookies or not. Should the iframe be same-origin as the top frame, the promise returns true.

var promise = document.hasStorageAccess();
promise.then(
  function (hasAccess) {
    // Boolean hasAccess says whether the document has access or not.
  },
  function (reason) {
    // Promise was rejected for some reason.
  }
);

Request Storage Access

A call to document.requestStorageAccess() upon a user gesture such as a tap or click returns a promise that is resolved if storage access was granted and is rejected if access was denied. If storage access was granted, a call to document.hasStorageAccess() will return true. The reason why iframes need to call this API explicitly is to offer developers control over when the document’s cookies change.

<script>
function makeRequestWithUserGesture() {
  var promise = document.requestStorageAccess();
  promise.then(
    function () {
      // Storage access was granted.
    },
    function () {
      // Storage access was denied.
    }
  );
}
</script>
<button onclick="makeRequestWithUserGesture()">Play video</button>

The iframe needs to adhere to a set of rules to be able to get storage access granted. The basic rules are:

  • The iframe’s cookies need to be currently partitioned by ITP. If they’re not, the iframe either already has cookie access or cannot be granted access because its cookies have been purged.
  • The iframe needs to be a direct child of the top frame.
  • The iframe needs to be processing a user gesture at the time of the API call.

Below are the detailed rules for the promise returned by a call to document.requestStorageAccess(). When we say eTLD+1 we mean effective top-level domain + 1. An eTLD is .com or .co.uk so an example of an eTLD+1 would be social.co.uk but not sub.social.co.uk (eTLD+2) or co.uk (just eTLD).

  1. If the sub frame is sandboxed but doesn’t have the tokens “allow-storage-access-by-user-activation” and “allow-same-origin”, reject.
  2. If the sub frame’s parent is not the top frame, reject.
  3. If the browser is not processing a user gesture, reject.
  4. If the sub frames eTLD+1 is equal to the top frame’s eTLD+1, resolve. As an example, login.socialexample.co.uk has the same eTLD+1 as www.socialexample.co.uk.
  5. If the sub frame’s origin’s cookies are currently blocked, reject. This means that ITP has either purged the origin’s website data or will do so in the near future. Thus there is no storage to get access to.
  6. If all the above has passed, resolve.

Access Removal

Storage access is granted for the life of the document as long as the document’s frame is attached to the DOM. This means:

  • Access is removed when the sub frame navigates.
  • Access is removed when the sub frame is detached from the DOM.
  • Access is removed when the top frame navigates.
  • Access is removed when the webpage goes away, such as a tab close.

Sandboxed Iframes

If the embedding website has sandboxed the iframe, it cannot be granted storage access by default. The embedding website needs to add the sandbox token “allow-storage-access-by-user-activation” to allow successful storage access requests. The iframe sandbox also needs the tokens “allow-scripts” and “allow-same-origin” since otherwise it can’t call the API and doesn’t execute in an origin that can have cookies.

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

A Note On Potential Abuse

We have decided not to prompt the user when an iframe calls the Storage Access API to make the user experience as smooth as possible. ITP’s rules are an effective gatekeeper for who can be granted access, and for the time being we rely on them.

However, we will monitor the adoption of the API and make changes if we find widespread abuse where the user is clearly not trying to take some authenticated action in the calling iframe. Such API behavior changes may be prompts, abuse detection resulting in a rejected promise, rate limiting of API calls per origin, and more.

Availability

Storage Access API is available in Safari 11.1 on iOS 11.3 beta and macOS High Sierra 10.13.4 beta, as well as in Safari Technology Preview 47+. If you’re interested in cross-browser compatibility, please follow the whatwg/html issue for Storage Access API.

Feedback

Please report bugs through bugs.webkit.org, or send feedback on Twitter to the team @webkit, or our evangelist @jonathandavis. If you have technical questions about how the Storage Access API works, you can find me on Twitter @johnwilander.