Search code examples
javascriptiframesafaristorage-access-api

Cannot set cookie in iframe using the Storage Access API on Safari


I have an iframe on my page. As Safari blocks 3rd party cookies, I am trying to use the Storage Access API as suggested here under 'Developer Guidance': https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/. I have copied the following code from the documentation:

<script type="text/javascript">
  window.addEventListener('load', () => {
    document.getElementById('test-button').addEventListener('click', () => {
      document.hasStorageAccess().then(hasAccess => {
        console.log('hasAccess: ' + hasAccess);
        if (!hasAccess) {
          return document.requestStorageAccess();
        }
      }).then(_ => {
        console.log('Now we have first-party storage access!');
        document.cookie = "foo=bar";
        console.log(`document.cookie: ${document.cookie}`);
      }).catch(_ => {
        console.log('error');
      });
    });
  });
</script>

<button id="test-button">Test</button>

Browser console output:

[Log] hasAccess: true
[Log] Now we have first-party storage access!
[Log] document.cookie: 

As you can see, the grant seems to be successful but still cannot set the cookie. Does anyone have an idea what's wrong?

Safari Version 13.0.1

EDIT: Console output on Safari 13.1:

[Log] hasAccess: false
[Log] error

Note: The enclosing page is a simple iframe tag with a src pointing to this page.


Solution

  • TL;DR

    Make sure a cookie has already been set for the domain in a first-party context.


    There's a couple of things to look out for with that code sample. Please note the following was tested on Safari 13.1.

    Conditions of a user prompt, and subsequent access grant:

    1. document.requestStorageAccess has to be called as a result of a user action. Despite as documented on the MDN docs, document.hasStorageAccess does not seem to propagate the user action.
    2. The user must have interacted with the third party in a first party context already. Any click on the document will do.

    Conditions of being able to write a cookie:

    A cookie must have already been set on the domain in a first party context. This cookie can either be set by the server as a response header, or by JS using document.cookie. With a bit of further testing, it seems this cookie MUST NOT be set with the domain flag in order for a subsequent cookie to be set in the third party context. This means that in effect, the existing cookie must also be set on the same exact sub domain.