Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Safari iframe cookie workaround
<?php
header("Location: " . $_GET['redirect']);
setcookie("__trust");
<?php
if (!isset($_COOKIE['testcookie']))
echo "Cookie not set!";
else if ($_COOKIE['testcookie'] != $_GET['cookie'])
echo "Cookies don't match: " . $_COOKIE['testcookie'] . ' != ' . $_GET['cookie'];
else
echo "Cookies match!";
<?php
$value = uniqid();
setcookie("testcookie", $value);
echo "<p>Now go <a href='dest_get.php?cookie=" . $value . "'>here</a></p>";
<?php
$internalPath = "http://local.test/path";
$externalPath = "http://remote.test/path";
?>
<html><head><title>Redirect Cookie Test</title></head>
<body>
<?php if ($_GET['redirected']): ?>
<p>iframe starts below...</p>
<iframe src="<?= $externalPath ?>/dest_set.php"?>
<?php else: ?>
<a href="<?= $externalPath ?>/dest_bounce.php?redirect=<?= $internalPath ?>/src.php?redirected=true">Bounce here...</a>
<?php endif; ?>
</body>
@kevinvos

This comment has been minimized.

Copy link

kevinvos commented Oct 27, 2017

Nice catch, thanks for the explanation! I've discovered the same problem which magically solved itself, now I know why and how :).

@RaiserWeb

This comment has been minimized.

Copy link

RaiserWeb commented Nov 20, 2017

This indeed works. One issue it presents is that Google Analytics tracking is lost, and counts the visit as being referred from the remote.test domain. I'm trying to work out how to get GA to ignore this redirection but no luck thus far.

@mattharley

This comment has been minimized.

Copy link

mattharley commented Nov 29, 2017

Unsure if this still works but there is a Javasctipt-only solution https://github.com/vitr/safari-cookie-in-iframe

Works on the same principal but does the redirect on the page underneath the iFrame without needing to hit the server.

@Enalmada

This comment has been minimized.

Copy link

Enalmada commented Nov 30, 2017

I just put something in an iframe and was pulling my hair out that some users were reporting issues...turned out to be this. Thank you very much for taking the time to do this write up. Also very thankful for the "safari-cookie-in-iframe" reference....here is what I went with based on that:

PARENT

var is_safari = navigator.userAgent.indexOf("Safari") > -1;
// Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
if ((is_chrome) && (is_safari)) {is_safari = false;}  
if (is_safari) {
    // See if cookie exists (https://stackoverflow.com/a/25617724/1502448)
    if (!document.cookie.match(/^(.*;)?\s*fixed\s*=\s*[^;]+(.*)?$/)) {
        // Set cookie to maximum (https://stackoverflow.com/a/33106316/1502448)
        document.cookie = 'fixed=fixed; expires=Tue, 19 Jan 2038 03:14:07 UTC; path=/';
        window.location.replace("http://vit-demos.appspot.com/_safari_fix.html");
    }
}

CHILD

document.cookie = 'safari_cookie_fix=true; path=/';
window.location.replace(document.referrer);
@jloguercio

This comment has been minimized.

Copy link

jloguercio commented Jun 3, 2018

I can't make this work with the solution : https://github.com/vitr/safari-cookie-in-iframe , i create have an site B in a Iframe in A, so in A i write this code :

var is_safari = navigator.userAgent.indexOf("Safari") > -1;
// Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
if ((is_chrome) && (is_safari)) {is_safari = false;}  
if (is_safari) {
    // See if cookie exists (https://stackoverflow.com/a/25617724/1502448)
    if (!document.cookie.match(/^(.*;)?\s*fixed\s*=\s*[^;]+(.*)?$/)) {
        // Set cookie to maximum (https://stackoverflow.com/a/33106316/1502448)
        document.cookie = 'fixed=fixed; expires=Tue, 19 Jan 2038 03:14:07 UTC; path=/';
        window.location.replace("http://vit-demos.appspot.com/_safari_fix.html");
    }
}

and create a file called _safari_fix.html with this code :

document.cookie = 'safari_cookie_fix=true; path=/';
window.location.replace(document.referrer);

but the workaround doesn't work

@datthepirate

This comment has been minimized.

Copy link

datthepirate commented Jul 20, 2018

Does this still work in 2018?

@bktan81

This comment has been minimized.

Copy link

bktan81 commented Aug 1, 2018

tried and it works

@dawolf

This comment has been minimized.

Copy link

dawolf commented Aug 6, 2018

This stopped working for me with the latest Safari on macOS Version 11.1.2 (13605.3.8)

Session cookie in a iframe will be dropped if the domain in the iframe has not been visited before.

@fbricenho

This comment has been minimized.

Copy link

fbricenho commented Sep 20, 2018

I just put something in an iframe and was pulling my hair out that some users were reporting issues...turned out to be this. Thank you very much for taking the time to do this write up. Also very thankful for the "safari-cookie-in-iframe" reference....here is what I went with based on that:

PARENT

var is_safari = navigator.userAgent.indexOf("Safari") > -1;
// Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
if ((is_chrome) && (is_safari)) {is_safari = false;}  
if (is_safari) {
    // See if cookie exists (https://stackoverflow.com/a/25617724/1502448)
    if (!document.cookie.match(/^(.*;)?\s*fixed\s*=\s*[^;]+(.*)?$/)) {
        // Set cookie to maximum (https://stackoverflow.com/a/33106316/1502448)
        document.cookie = 'fixed=fixed; expires=Tue, 19 Jan 2038 03:14:07 UTC; path=/';
        window.location.replace("http://vit-demos.appspot.com/_safari_fix.html");
    }
}

CHILD

document.cookie = 'safari_cookie_fix=true; path=/';
window.location.replace(document.referrer);

Does this still working?

@ricklambrechts

This comment has been minimized.

Copy link

ricklambrechts commented Nov 7, 2018

The javascript workaround still works!

@shazadmaved

This comment has been minimized.

Copy link

shazadmaved commented Feb 23, 2019

With the javascript workaround, The first access gets into a redirect loop in safari :| , could anyone suggest something that must be wrong. The second access onwards it works fine. For some reason during the redirect the "fixed" cookie that is set is not being fetched.

@thomasdarde

This comment has been minimized.

Copy link

thomasdarde commented Apr 3, 2019

this solution is nice and works , but an important caveat is found if the page is called from a "post" url. The return won't work.
window.postmessage is a good solution to share data between iframe and parent.

@allenlinli

This comment has been minimized.

Copy link

allenlinli commented Apr 17, 2019

Should we fire a radar to Apple for this Safari feature(bug)?

@allenlinli

This comment has been minimized.

Copy link

allenlinli commented Apr 17, 2019

I think maybe we can't... https://discussions.apple.com/thread/4156939
I just can't figure what could iframe cookie threat users using Safari.

@SebT

This comment has been minimized.

Copy link

SebT commented Aug 1, 2019

The JS workaround works on MacOS but not on iOS (iPad). Does anyone have a similar problem ?

@raj-uimatic

This comment has been minimized.

Copy link

raj-uimatic commented Jan 3, 2020

My cookie does not carry forward data from one iframe to another in safari, I have a scenario like this:
I have parent domain ex: website.com , Inside that I have a iframe with this url ex. parent.com where I am setting cookie for parent while submitting form so I am setting cookie like this domain=".parent.com" (so it will set cookie for subdomain automatically)

When form is submitted I move to another page like website2.com and inside that page I have a iframe with subdomain like parent.child.com Now issue is I am not able to get cookie which were set by parent.com in safari

Please help! other browser works great

Thanks

@tgiordmaina

This comment has been minimized.

Copy link

tgiordmaina commented Mar 2, 2020

It seems safari is the new IE.. what a weird behavior, I'm tired, 3 days I tried to solve that, I need to rebuild all my authentication system because of that. TY apple, if anyone as a solution not a workaround it will be great. Thanks

@WebSpectrum

This comment has been minimized.

Copy link

WebSpectrum commented Mar 16, 2020

Hi All - what is the best solution to date if you don't have control or ability to deploy code on site B ? ....

@tgiordmaina

This comment has been minimized.

Copy link

tgiordmaina commented Mar 16, 2020

I used a popup to do the trick (by temporary passing the cookie as parameter to a third party API).
If you have full control on site B (code + DNS) I advice you to declare a subdomain in you site B which forward silently to your wished website/API (add a new AAAA entry with your service IP) :

       +------------------+                          +-----------------------+
       |                  |   XHR with credentials   |                       |
       |  www.siteB.com   --------------------------->  api-siteA.siteB.com  |
       |                  |                          |                       |
       +------------------+                          +-----------------------+
@russau

This comment has been minimized.

@mwleinad

This comment has been minimized.

Copy link

mwleinad commented Apr 7, 2020

Any idea if there's a workaround with safari 13.1?

@antstorm

This comment has been minimized.

Copy link

antstorm commented Apr 12, 2020

Looks like requesting storage access via their APIs is the way to do it — https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/

@Arcolye

This comment has been minimized.

Copy link

Arcolye commented Apr 29, 2020

What a fantastic time to put this extra hurdle on struggling and furloughed development teams. Thanks Apple, Safari, and specifically John Wilander!

With brick-and-mortar businesses struggling and software companies doing what they can to help out, NOW was the time to release this huge software-breaking change? Not 2022 like Chrome has roadmapped? Now? During the Covid recession? And with "Storage Access API" still in a poorly-documented and experimental phase? Now?

Badly done, Safari. Badly done indeed. Shame on you, John Wilander.

@asecondwill

This comment has been minimized.

Copy link

asecondwill commented May 1, 2020

The workarounds seem to work, but not in webkit view in eg facebook/twitter/instagram webviewer. And clues on what to do would be ace.

@stevenlawrance

This comment has been minimized.

Copy link

stevenlawrance commented May 5, 2020

From https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/, it appears that a workaround that uses OAuth2 may exist, though it's not exactly clear how to invoke this (and using Secure+HttpOnly cookies isn't sufficient to make it work). I'll have to poke around the WebKit source code..

Option 1: OAuth 2.0 Authorization with which the authenticating domain (in your case, the third-party that expects cookies) forwards an authorization token to your website which you consume and use to establish a first-party login session with a server-set Secure and HttpOnly cookie.

@github-xuser

This comment has been minimized.

Copy link

github-xuser commented May 19, 2020

I have a workaround based on an interface to sagepay.
We tell sagepay where to return to after CC entry in an iframe, Once the user submits the CC form to sagepay, they redirect the iframe to us and we take over control of the iframe and close it.
Unless its the latest safari. Then the iframe redirect happens, but with no session cookie so our software has no continuity and terminates because it thinks the session has timedout. Not very good when someone is trying to buy something in your shop.
I already implemented a change so that the iframe was created with a page from our domain which then redirects to sagepay, so i know that safari has the correct session cookie in the iframe. This did actually fix quite a lot of the problems but not all.
My thought for fixing them all was that safari doesnt like sending the correct session cookie when sagepay redirects back to our domain, but i wonder what will happen if i make the redirect from sagepay simply do another redirect from us, to us.
It worked, on the second redirect from our domain to our domain the session cookie is correct.
That has to be a bug in safari.
So if i am dom1.com and sagepay is dom2.com the fix is:
Create an iframe with src = dom1.com/redirect1 this simply contains html or javascript to do the correct redirect to your dom2.com page.
Tell dom2.com to return to dom1.com/dummyredirect. dummyredirect copies all the querystring or post data and returns a page that redirects back to dom1.com/theproperreturnaddress.
Its passed all our tests so far.
I hope it helps someone else, I can't see safari getting fixed or even acknowledging the bug anytime soon.

@xabier98

This comment has been minimized.

Copy link

xabier98 commented May 20, 2020

Hi

Please ¿can you explain or write an small example with your solution?

Thank you

Best Regards

@engelmav

This comment has been minimized.

Copy link

engelmav commented May 26, 2020

What a fantastic time to put this extra hurdle on struggling and furloughed development teams. Thanks Apple, Safari, and specifically John Wilander!

With brick-and-mortar businesses struggling and software companies doing what they can to help out, NOW was the time to release this huge software-breaking change? Not 2022 like Chrome has roadmapped? Now? During the Covid recession? And with "Storage Access API" still in a poorly-documented and experimental phase? Now?

Badly done, Safari. Badly done indeed. Shame on you, John Wilander.

Fascinating. The economic impact of code changes... should be factored in with behemoth applications and firms like Safari/Apple.

@jhud

This comment has been minimized.

Copy link

jhud commented May 30, 2020

Hi everyone, commiserations to those of you who also got blindsided by this during all the other Covid-19 IT dramas. Anyway, here is my quick fix for this.

Note that you cannot nest the document.hasStorageAccess, otherwise it misses the user interaction, so I don't bother checking - I run the code every time. I dropped this code inside my iframe. It needs to be triggered from an onClick, ie:

 <div onclick="safariFix();">If you have problems logging in on Safari, please click here.</div>

But instead I call this directly from my login form:

  <input type="submit" onclick="safariFix();" id="login_submit_button" value="{% trans 'Log in' %}" />

The first login fails because Safari pops up a non-blocking "do you want to allow..." popup, but it'll suffice until there's a fix that won't pollute the UI with some "click this if you are on Safari" button.

<script>
  // Safari now suddenly blocks iframe cookie access, so we need to call this during some user interaction
  function safariFix() {
    if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) {
      document.requestStorageAccess().then(() => {
          // Now we have first-party storage access!
          console.log("Got cookie access for Safari workaround");
          // Let's access some items from the first-party cookie jar
          document.cookie = "foo=bar";              // drop a test cookie
        },  () => { console.log('access denied') }).catch((error) => {
          // error obtaining storage access.
          console.log("Could not get access for Safari workaround: " + error);
        });
      }
  }
</script>

Apologies for the messiness - it's Saturday night and I just need to rush this out now so my customers can start making money again.

@openfermentation

This comment has been minimized.

Copy link

openfermentation commented Jun 5, 2020

The economic impact of code changes... should be factored in with behemoth applications and firms like Safari/Apple.

Not just economic, but very real health impact. My company delivers healthcare related information to patients, including COVID-19 content. We act as a third party to health plans and it's an all too common practice for this industry to integrate within iframes.

As it stands, patients using Safari can't access our content due to this security change. Content like ours has been shown to improve health outcomes. If you use Safari you might suffer a worse outcome in the event of a health crisis.

looks like requesting storage access via their APIs is the way to do it

The storage access API in Safari will flat out reject requestStorageAccess() if the client hasn't visited the third-party in first-party context AND has interacted with the site — https://stackoverflow.com/questions/52173595/how-to-debug-safari-itp-2-0-requeststorageaccess-failure

Interestingly, Firefox's implementation doesn't appear to enforce this same requirement, only adding to the confusion.

The majority of our users don't know who we are and have never visited our domain directly. The Storage Access API is clearly designed to accommodate social media network workflows. The rest of us are getting steamrolled.

@lenusch

This comment has been minimized.

Copy link

lenusch commented Jul 5, 2020

Does it work now? Is there a functional workarround? I didn't get this to work until now :-(

@sarayaz

This comment has been minimized.

Copy link

sarayaz commented Jul 8, 2020

Does anybody have solution for this in safari 13+ ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.