WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED WORKSFORME
241803
Safari throws exception when calling requestStorageAccess
https://bugs.webkit.org/show_bug.cgi?id=241803
Summary
Safari throws exception when calling requestStorageAccess
Jason Wilson
Reported
2022-06-21 06:59:34 PDT
I have to say Safari's (webkit) implementation of Intelligent Tracking Protection (ITP) and the Storage Access API has been challenging to get right. Situation: - We have a company that has grown through acquisition and we are trying to implement a unified authentication scheme that uses cross-domain access to tokens stored in cookies - Each portal implementing the scheme will have an iframe that hosts a component from an authentication domain and will use **postMessage()** to check for the existence of the necessary authentication token. - The initial implementation worked for Chrome/Edge/Opera/other Chromium browsers, but needed to be adjusted to implement the Storage Access API to allow the authentication component to request 1st party storage access. - This worked as documented in Firefox - Safari throws an exception when **requestStorageAccess()** is called and the error object is undefined Here is some examples of the relevant code: **Iframe** ``` html <iframe class="portal-navigation-frame" allowtransparency="true" style="position:absolute; top: -60px; right: -250px;display:none;" id="authFrame" sandbox="allow-scripts allow-storage-access-by-user-activation allow-same-origin allow-top-navigation allow-forms" src="@Constants.AuthenticationUrl"></iframe> ``` **Authentication Component** ``` javascript const authorizeStorageAccess = async () => { if (document.hasStorageAccess) { try{ if (await document.hasStorageAccess() == false) { console.log("authCommunicationService.authorizeStorageAccess", "does not have storage access"); if (document.requestStorageAccess) { await document.requestStorageAccess(); } else { console.log("authCommunicationService.authorizeStorageAccess", "requestStorageAccess not available"); } } else { console.log("authCommunicationService.authorizeStorageAccess", "already has access"); } } else { console.log("authCommunicationService.authorizeStorageAccess", "already has automatic access"); } catch (err) { console.log("authCommunicationService.authorizeStorageAccess", "error", err); } } }; ``` Note: **authorizeStorageAccess()** is called from a button event handler and only after the user has been redirected to the authentication domain to login and returned. Any assistance would be greatly appreciated. Jason
Attachments
Add attachment
proposed patch, testcase, etc.
John Wilander
Comment 1
2022-06-21 08:26:58 PDT
Hi! Thanks for filing. We have published a guide to help with adoption of the API. See "How To Use the Storage Access API" here:
https://webkit.org/blog/11545/updates-to-the-storage-access-api/
Let us know if you still have problems.
Jason Wilson
Comment 2
2022-06-21 08:31:10 PDT
Thank you . I've read the guide several times. The problem is that safari throws an exception when requestStorageAccess is called but the error object thrown is undefined so it is impossible to troubleshoot.
John Wilander
Comment 3
2022-06-21 08:33:27 PDT
Does the console in Web Inspector say anything? To help you, we need to decide what to call the site you are loading in the iframe and what to call the site where the iframe is embedded. It can be the real domain names of those sites but doesn't have to be as long as we can refer to them as distinctly.
Jason Wilson
Comment 4
2022-06-21 09:34:39 PDT
It logs the that it doesn't have access to storage and then catches an exception when requestStorageAccess is called, but says the err object is undefined. Here's an image to the console:
https://imgur.com/a/23QEOLA
John Wilander
Comment 5
2022-06-22 16:14:33 PDT
Those are your own console messages. I’m looking for console messages from the browser. Let’s also get the domains. See my request above.
Jason Wilson
Comment 6
2022-06-23 13:28:33 PDT
I'm not sure I understand. When I don't catch the exception, I get the message "Unhandled Promise Rejected: undefined". If I catch the error and look at the error object, it is undefined. We can call the embedded address start.flashparking.com and the host address portal.flashparking.com.
Jason Wilson
Comment 7
2022-06-27 05:26:30 PDT
This is a show stopper on a major authentication project. Is there anything that you can suggest?
John Wilander
Comment 8
2022-06-27 06:54:23 PDT
(In reply to Jason Wilson from
comment #6
)
> I'm not sure I understand. When I don't catch the exception, I get the > message "Unhandled Promise Rejected: undefined". > > If I catch the error and look at the error object, it is undefined. > > We can call the embedded address start.flashparking.com and the host address > portal.flashparking.com.
I checked the Public Suffix List (
https://publicsuffix.org/list/public_suffix_list.dat
) and flashparking.com is not a public suffix. This means that start.flashparking.com and portal.flashparking.com are just cross-origin and not cross-site. You therefore don't have to call the Storage Access API because you already have cookie access on start.flashparking.com under portal.flashparking.com. If these domains were just made up as an example, please provide the real domain names so that we can establish whether or not you need to call the Storage Access API. Thanks!
John Wilander
Comment 9
2022-06-27 06:57:45 PDT
(In reply to Jason Wilson from
comment #6
)
> I'm not sure I understand. When I don't catch the exception, I get the > message "Unhandled Promise Rejected: undefined".
There's a difference between what your JavaScript code sees through objects and what you as a developer can see in Web Inspector's console. There are certain warnings and errors that should not be exposed to code since they can be user against the user. Take for instance the reason for why there is no cookie access. If the code gets to know that the user explicitly refused to provide cookie access, that can potentially be used to pressure the user. This has already happened so it's a known problem. Therefore, look in Web Inspector's console for any additional information.
Jason Wilson
Comment 10
2022-06-27 07:53:35 PDT
I'm not seeing anything of note in the web inspector except what I've mentioned. I should also mention that it never prompts the user to allow storage access. It just errors when requestStorageAccess is called with no feedback. The mac I'm testing on is not my development system, but here's a picture of the entire console:
https://imgur.com/a/xvsQpDh
Jason Wilson
Comment 11
2022-06-27 07:57:48 PDT
Here's an image of the actual code called by the page hosted in the iframe. Line 20 is where the exception occurs:
https://imgur.com/a/NC39tnR
John Wilander
Comment 12
2022-06-27 16:44:07 PDT
We have still not established that you need to use the Storage Access API at all since the domains you provided are same-site. (In reply to Jason Wilson from
comment #11
)
> Here's an image of the actual code called by the page hosted in the iframe. > Line 20 is where the exception occurs:
https://imgur.com/a/NC39tnR
You should not call hasStorageAccess() upon a user gesture. You can only successfully call requestStorageAccess() upon a user gesture. From the guide I linked to above: Make your cross-site iframe call document.hasStorageAccess() as soon as it’s rendered to check your status. Note: Don’t call this function upon a user gesture since it’s asynchronous and will consume the gesture. Once the user gesture is consumed, making a subsequent call to document.requestStorageAccess() will fail because it’s not called when processing a user gesture. If document.hasStorageAccess() returns false, your iframe doesn’t have storage access. Now set an event handler on elements that represent UI which requires storage access and make the event handler call document.requestStorageAccess() on a tap or click. This is the API that requires a user gesture.
Jason Wilson
Comment 13
2022-06-28 04:41:49 PDT
Sorry, the domains are different. For the test app the domains are the following: - 3rd Party Page:
https://sp-1729-component-api.d2vtqpn78oqsy5.amplifyapp.com/
- 1st Party Page:
http://unifiedloginsample.azurewebsites.net/
requestStorageAccess is being called in a button click handler and the button resides in the 3rd party page. I'll go ahead and try removing the hasStorageAccess from the handler. I am calling both there.
Jason Wilson
Comment 14
2022-06-28 05:22:28 PDT
Removing the call to hasStorageAccess from the event handler did the trick. I am pretty excited. Thanks for your help.
Jason Wilson
Comment 15
2022-06-28 06:31:21 PDT
Another question -- for testing purposes, is it possible to remove the storage access once granted?
John Wilander
Comment 16
2022-06-28 06:43:49 PDT
(In reply to Jason Wilson from
comment #15
)
> Another question -- for testing purposes, is it possible to remove the > storage access once granted?
There’s no programmatic way to do it since it’s a user decision to grant access. However, the access can age out if the user stops interacting with the site or the embedded content.
John Wilander
Comment 17
2022-06-28 06:44:45 PDT
Glad we could make this work for you!
Jason Wilson
Comment 18
2022-06-28 13:42:49 PDT
Is there a way for me to do it as a user, waiting for it age out definitely will slow down testing
John Wilander
Comment 19
2022-06-28 15:42:09 PDT
(In reply to Jason Wilson from
comment #18
)
> Is there a way for me to do it as a user, waiting for it age out definitely > will slow down testing
You can test in Private Mode which forgets everything at browser restart. Just make sure you do the whole flow in the same tab since Private Mode is separated by tab. Or you can delete your browsing history. If you don’t want to clear your own, real browsing history, you can use a separate Safari instance under a different macOS account or Safari Technology Preview.
Jason Wilson
Comment 20
2022-06-30 12:56:34 PDT
I thought it was supposed to remember that page in the IFrame has storage access, but I having to request each time I reload the page. Again this works just fine in Firefox which also has an implementation of the Storage Access API. Jason
Jason Wilson
Comment 21
2022-06-30 13:01:11 PDT
Also if the url changes at all. I have to request storage access -- even if the change is just a change in the query string params
John Wilander
Comment 22
2022-06-30 15:29:23 PDT
(In reply to Jason Wilson from
comment #20
)
> I thought it was supposed to remember that page in the IFrame has storage > access, but I having to request each time I reload the page. > > Again this works just fine in Firefox which also has an implementation of > the Storage Access API. > > Jason
Yes, WebKit uses per-page scope whereas Gecko has a more relaxed model. Both are allowed and have been discussed extensively. WebKit’s position is that just because the user allows a third party to identify them on one page doesn’t mean they allow it for all pages on that site. As an example, imagine the user wants to comment on a story on news.example with their social.example account. That does not imply that the user henceforth wants social.example to identify them on all pages on news.example and be able to track all the news they read there.
Jason Wilson
Comment 23
2022-07-01 05:27:48 PDT
Unfortunately it makes it useless for our cross-domain authentication. Is there something in the proposed standard that allows for sites to opt out of the ITP if they control both domains -- perhaps allow iframes sandboxed with allow-same-origin to access 1st party storage. Our company has grown significantly in the last 2 years through acquisition and right now consolidating under a single domain isn't an option. Cross-domain authentication is an intermediate step for us while we implement other auth schemes that don't use 3rd party cookies, but it's a necessary step.
John Wilander
Comment 24
2022-07-01 06:45:44 PDT
(In reply to Jason Wilson from
comment #23
)
> Unfortunately it makes it useless for our cross-domain authentication. Is > there something in the proposed standard that allows for sites to opt out of > the ITP if they control both domains -- perhaps allow iframes sandboxed with > allow-same-origin to access 1st party storage.
There is no such affordance since there is no trustworthy way for a browser to know that two domains belong to the same company.
> Our company has grown significantly in the last 2 years through acquisition > and right now consolidating under a single domain isn't an option. > Cross-domain authentication is an intermediate step for us while we > implement other auth schemes that don't use 3rd party cookies, but it's a > necessary step.
A major challenge here, which has been discussed at length in web standards, is that users have no reasonable way of knowing that two domains belong to the same company. Users also don’t expect a login on one site to invisibly log them in on another. We typically advice developers to establish login tokens on the first party website where the user interacts instead of trying to maintain it as third-party. You make a transaction between the domains and then keep the login state as first party website.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug