Javascript – Safari 13+ iframe blocks CORS cookies

cookiescorsiframejavascriptsafari

Safari flat out doesn't let you set cookies in iframes of domains different than the parent domain, server-side CORS headers be damned.

To clarify: user is on domainA.com. An iframe for domainB.com is open,
and attempts to authenticate the user on domainB.com inside the
iframe. Set-Cookie header is returned from the server inside the domainB.com iframe, with all the required headers, but Safari isn't sending it back in subsequent calls.

An old workaround was doing a form submit from the iframe, and set the cookie in the response. I guess they liked the fact that the user was clicking something to submit the form. You'd have to poll for the cookie to see when the response came back, as form submits have no callbacks, and in the case of HttpOnly cookies you couldn't, but hey, it worked! Until it didn't.

Then, a more recent workaround was redirecting the user to the iframe domain in a brand new window/tab, setting a random cookie there, and from that moment on, that subdomain was "trusted" inside the iframe. Again, it required a click to open the new window/tab, and there was even a visual indication of the new tab opening. Much security, such standards.

And now, as of Safari 13 – No more workaround. No more secure iframe cookie setting 🤬

Any other authentication scheme isn't good for us (e.g. Auth-X header). We need to use an HttpOnly secure cookie, as we don't want that token to be in any way accessible by javascript client-side.

To be clear, everything works great on any other browser.

Relevant WebKit Bugzilla

Does anyone have any suggestions?

Edit:

Thanks for the link @tomschmidt, that seems like the right direction.
I tried using Apple's Storage Access API, but unfortunately, although I'm making sure to request access before initializing my login logic with the API:

requestStorageAccess = async() => {
    return new Promise(resolve => {
      //@ts-ignore
      document.requestStorageAccess().then(
        function () {
          console.log('Storage access was granted');
          resolve(true);
        },
        function () {
          console.log('Storage access was denied');
          resolve(false);
        }
      );    
    });
  }


const storageAccessGranted = await requestStorageAccess();
console.log(storageAccessGranted) // prints 'true'
await login();

Still, the cookies received on the /login API response are not getting sent in subsequent calls to the API 🙁

Edit 2 (May 2021):

Safari 14 has added another breaking change:

https://webkit.org/blog/11545/updates-to-the-storage-access-api/

Go Apple go! You're making us reminisce about IE6.

Best Answer

I think I might have found the solution: Apple's Storage Access API: https://webkit.org/blog/8124/introducing-storage-access-api/