Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interacting with embedded applications as top-level prior to granting permission #9

Open
andywang219 opened this issue Oct 5, 2023 · 24 comments

Comments

@andywang219
Copy link

andywang219 commented Oct 5, 2023

Hi @cfredric,

I am trying to get a better understanding for the error message: Request denied because the embedded site has never been interacted as a top-level context.

My questions are:

  1. What actions are considered as an interaction? Does visiting the site as a top-level context suffice or does the user need to click around?
  2. Is there a workaround for this? In the scenario where an application is completely hidden from the end user, this might pose some issues because now the end user needs to interact with a site that they never knew they were using.
  3. Who are considered to be new users when determining if the user needs to interact with the embedded site as top-level? If we have company A and B, and company B embeds company A as a third-party site. If an user at company B has interacted with company A as the top-level site, will every other user at company B be required to interact with A as the top-level site?

As an example for question 2, company A has a chat widget that also comes with APIs where developers can use to interact with said widget. Company A provides the option to hide the default chat widget from the HTML and allow company B to build their own UI and then interact with the chat widget via the APIs. The default chat widget becomes a proxy in this use case. Now with requestStorageAccess, users have to interact with the default widget in order to be granted permission.

@cfredric
Copy link
Owner

cfredric commented Oct 6, 2023

Hi @andywang219,

I'll jump right into your questions:

  1. What actions are considered as an interaction? Does visiting the site as a top-level context suffice or does the user need to click around?

A user interaction (aka activation or user gesture) is something defined by the HTML standard. It lists the different kinds of interactions here: keypresses, mouse clicks, and touch events.

  1. Is there a workaround for this? In the scenario where an application is completely hidden from the end user, this might pose some issues because now the end user needs to interact with a site that they never knew they were using.

There's no workaround for this in Chrome, if your application requires read/write access to unpartitioned state (and therefore really requires the Storage Access API). If an embedded cross-site application needs to access unpartitioned state (e.g. a user identifier), then the user ought to know that the application exists, and be aware that they're interacting with it.

(Just for context: the top-level user interaction requirement is to protect Chrome users from prompts that come from sites which the users have never heard of and have no intention of using. This is an attempt to avoid the kind of spam we've seen through push notifications prompts, for example.)

  1. Who are considered to be new users when determining if the user needs to interact with the embedded site as top-level? If we have company A and B, and company B embeds company A as a third-party site. If an user at company B has interacted with company A as the top-level site, will every other user at company B be required to interact with A as the top-level site?

"Users" for these purposes are individual browser profiles in Chrome. If one Chrome profile/user interacts with company A, that is not sufficient to conclude that every Chrome profile/user is ok with seeing prompts from company A while it's embedded under another site (e.g. company B's site). So yes, every other Chrome user who visits company B's site and needs to use the company A embed will have to interact with company A's site in a top-level context beforehand.


I want to point out an important detail here though - my response to your second question said "if your application requires read/write access to unpartitioned state". You never mentioned needing to share your application's state regardless of which top-level site it's embedded under (e.g. A embedded under B, vs A embedded under C), so it's possible you don't actually need unpartitioned state. If you don't need to share that state, then partitioned state might be ok for you. In that case, I'd recommend checking out CHIPS, which require neither a prompt nor an interaction in a top-level context.

Similarly, if you require unpartitioned state but don't need to be able to both read and write to it, you could check out some of the other Privacy Sandbox proposals (particularly Fenced Frames and Shared Storage) and see if they address your needs.

@bretticus-mc
Copy link

How are third-party authentication cookies using SAML/SSO supposed to work then?

We support an application that's embedded in customer websites as an iframe. The customer will authenticate with their SAML provider in the top-level context, which will perform a SAML assertion to our product to retrieve a third-party authentication cookie. With the coming change, we need to use the StorageAccessAPI to access that cookie from our iframe. However, our customers interact with our product solely in an embedded context. Therefore, Chrome will deny the requestStorageAccess call saying they've never interacted with our application as a top-level context. This requirement completely breaks our authentication flow, and I imagine many others who aren't aware of this coming change.

If an embedded cross-site application needs to access unpartitioned state (e.g. a user identifier), then the user ought to know that the application exists, and be aware that they're interacting with it.

The storageAccessAPI already requires a user gesture; so the customer already knows the application exists.

@cfredric
Copy link
Owner

cfredric commented Oct 9, 2023

How are third-party authentication cookies using SAML/SSO supposed to work then?

To my knowledge, we (Chrome) haven't yet seen an authenticated embed use case where the user is expected to never interact with the embedded site in a top-level context. In all the use cases we've seen, the user is brought through a flow that involves a login in a popup or some other top-level context (e.g. a redirect), which sets the unpartitioned cookie that gets accessed later on by the iframe. This flow is common enough that Firefox automatically grants storage access to any site that the user has interacted with in a top-level context; Safari also grants access in these situations, AFAIK. Chrome is prototyping this heuristic as well.

(On the subject of other browsers, what have you observed in browsers like Firefox and Safari which already block third-party cookies by default?)

We've also seen some use cases where the embedded iframe is invisible but still relies on the user's (unpartitioned) identity. Chrome and other browsers are still exploring the solution space for those scenarios; the latest proposal in this space is the Top-Level Storage Access API Extension, but this still assumes that the user will visit the embedded site as a top-level context to log in at some point.

Chrome also supports the FedCM API, which is an option for federated sign-in. This API does support usage from within an iframe, so if your application can use FedCM, it could be available to you in these iframes.

With all of this in mind, is it an option for you to open a top-level context (e.g. a popup) in which your users can log in, or at least click a "Proceed with <XYZ app>" button? If it is, then it would solve your problem, IIUC.

If an embedded cross-site application needs to access unpartitioned state (e.g. a user identifier), then the user ought to know that the application exists, and be aware that they're interacting with it.

The storageAccessAPI already requires a user gesture; so the customer already knows the application exists.

I was responding to @andywang219's "In the scenario where an application is completely hidden from the end user, this might pose some issues because now the end user needs to interact with a site that they never knew they were using" question (emphasis mine). This example shows why a user gesture in the embedded context cannot prove that the user knows that the embedded application exists. This is why that user gesture is necessary but not sufficient for getting the storage-access permission via document.requestStorageAccess in Chrome.

@jagadeeshaby
Copy link

@cfredric

Thanks for looking into the issue.

For a context its the same setup which we were discussing in the previous issues #6 . ( the one with videos and screenshots)

the only confusion here is the restrictions of site never been interacted as a top level context which is different from asking storage access with explicit grant access button interaction from the same site in an embedded context. In this case even though user s doing explicit interaction which isn't considered valid and rejected by RSA.

Yes our users always interacts( click) with embedded site which grants access to cookies set during SSO navigation.

Take an example of brand new chrome browser download, and first time user navigates to their company site which embeds third party site in question , which asks for storage access with explicit click interaction and then allow sso navigation to continue in a separate same site iframe or popup which sets un partitioned cookies( all 302s mostly) . In this flow explicit click action invokes rsa but fails with message that you never interacted with embedded site in top level, could u guide how to handle this use case? This goes away as soon as the user opens up embedded site once in a new tab, which i want to avoid.

@cfredric
Copy link
Owner

Thanks for the context.

the only confusion here is the restrictions of site never been interacted as a top level context which is different from asking storage access with explicit grant access button interaction from the same site in an embedded context. In this case even though user s doing explicit interaction which isn't considered valid and rejected by RSA.

To be clear, the Storage Access API in Chrome requires two distinct user interactions:

  1. A user interaction in the embedded site as a top-level, sometime within the last 30 days. This is some reassurance to the browser that the user has some existing relationship with the site, they know what it is, etc.
  2. A user interaction in the embedded site in the cross-site iframe, immediately before the call to document.requestStorageAccess.

Interaction #​1 is to reassure the browser that the user might actually have some relationship with the site in question. If the user has never interacted with the site in its own top-level context, the user is less likely to be familiar with the site in question. We (Chrome) want to be sure that when we show a permission prompt, the user has definitely heard of the site that's requesting permission. This is part of ensuring that the user understands as much as possible about the request.

Of course, a user interaction in a top-level context doesn't guarantee that the user is ok with that site asking for storage-access permission in the future. But it's at least a baseline requirement that Chrome can apply to protect the user from spammy permission prompts or prompts that they don't understand.

Interaction #​2 is a standard requirement for any permission prompt, and any powerful API in the web platform.

Yes our users always interacts( click) with embedded site which grants access to cookies set during SSO navigation.

Can you elaborate more on your SSO arrangement? How/when does the user sign into your application? Is it possible to do the sign-in before your application requests storage-access permission?

could u guide how to handle this use case? This goes away as soon as the user opens up embedded site once in a new tab, which i want to avoid.

I would recommend exactly what you said: opening the embedded site once in a new tab, before asking for storage-access permission. Are there constraints that make that difficult/impossible for you?

Coming at this from a different angle - in browsers that don't require the top-level interaction (Safari and Firefox, to my knowledge), what do you observe? Do your users understand the permission prompts and why they might want to grant or deny permission? How often do your users accept the prompt and continue with the SSO flow? How often do they deny permission or dismiss the prompt?

@andywang219
Copy link
Author

Hi @cfredric,

Could you clarify if the 30 days in Interaction #1 is a rolling 30 days or strict 30 days?
IE. Does the 30 days reset if the user interacts with the website as top-level on day 29?

@cfredric
Copy link
Owner

Hi @andywang219, I'm not sure what you mean by "rolling" vs "strict". But to hopefully answer your question anyway - at the time when document.requestStorageAccess is called, Chrome finds the timestamp of the most recent user interaction in the third-party site in a top-level context. If that timestamp is more than 30 days ago, Chrome rejects the document.requestStorageAccess call. Otherwise, Chrome prompts the user to allow/deny/dismiss the request.

So, if the user interacts with the site on day 0, then interacts with the site on day 29, then calls document.requestStorageAccess() on day 31, the most recent top-level user interaction on that site would be from day 29 which is less than 30 days from the present (day 31). So Chrome would show a prompt.

If instead, the user interacts with the site on day 0, then calls document.requestStorageAccess() on day 31, the most recent top-level user interaction on that site is from day 0 which is more than 30 days from the present (day 31). So Chrome would not show a prompt in this scenario, and would deny the request automatically.

@andywang219
Copy link
Author

Thank you for the clarification!

@andywang219
Copy link
Author

One follow up question, will Chrome expose an API to allow developers retrieve the timestamp that you mentioned?

@johannhof
Copy link

There's currently no proposal for that, however, you should be able to store this information in storage or cookies relatively easily, if it matters to you (I'm not really sure there's a use case for this).

@cfredric
Copy link
Owner

cfredric commented Nov 3, 2023

+1 to Johann's comment. I'd also add that if Chrome were to expose the most recent top-level interaction timestamp, and the embedded context were able to read it (before having called document.requestStorageAccess()), that would represent a cross-site data leak. (Being able to match up a timestamp like 1699018458019 between two visitors to your site is a pretty strong signal that it's actually the same visitor.) Chrome and other browsers are working to reduce passively-available cross-site signals like that, so I don't think such an API is likely to be built.

@andywang219
Copy link
Author

Got it, thank you both

@jagadeeshaby
Copy link

thank you @cfredric

Apologies for the delay in response.

A user interaction in the embedded site as a top-level, sometime within the last 30 days. This is some reassurance to the browser that the user has some existing relationship with the site, they know what it is, etc.

To me this doesn't sound right and not practical and makes it completely painful for our third party SASS applications.

Take an example of the typical SASS app usage, the whole point of embedded app is to take away the need for users to navigate to a different domain/tab and rather have it within the users workspace and work along side with other apps. (Example Call handling app along side with the CRM providers like Salesforce , zendesk or even customer own solution) so in this case asking users to open embedded site in a top level site is breaking the whole usability aspect of it.

in browsers that don't require the top-level interaction (Safari and Firefox, to my knowledge), what do you observe? Do your users understand the permission prompts and why they might want to grant or deny permission? How often do your users accept the prompt and continue with the SSO flow? How often do they deny permission or dismiss the prompt?

that's at least perfect for our SASS applications and Firefox and Safari does great in this area.

Do your users understand the permission prompts and why they might want to grant or deny permission?

Yes they do understand the prompt as we make it clear to them with a banner which asks to grant access and provides links to SASS app FAQs.

How often do your users accept the prompt and continue with the SSO flow?

At least from our data, it's Always.

How do we discuss further about making the top level interactions optional or follow the same model as safari or firefox to be consistent?

@cfredric
Copy link
Owner

Hi @jagadeeshaby,

To me this doesn't sound right and not practical and makes it completely painful for our third party SASS applications.

Take an example of the typical SASS app usage, the whole point of embedded app is to take away the need for users to navigate to a different domain/tab and rather have it within the users workspace and work along side with other apps. (Example Call handling app along side with the CRM providers like Salesforce , zendesk or even customer own solution) so in this case asking users to open embedded site in a top level site is breaking the whole usability aspect of it.

To be clear, the requirement of an interaction in a top-level context is only necessary if your embedded application needs to use unpartitioned state. Unpartitioned state is particularly sensitive because it allows an embedded site/app to track a user as they browse the web.

If your SaaS (I assume this is what you mean instead of SASS?) application does not need unpartitioned state, then it can freely use partitioned cookies and partitioned storage without needing to prompt the user and without the user visiting it as a top-level site.

With that in mind, I'd like to understand your application's requirements better, to understand the following:

  1. Why an application (which is always embedded) needs access to unpartitioned state?
  2. How you ensure that the user understands what your application is and why they might want to enable/use it, given that the user never visits your site in a top-level context?

If I understand correctly, the only reason for a SaaS app (which is always embedded) to require access to unpartitioned state would be if the app is embedded under multiple top-level sites and needs to recognize a single user as they visit multiple of those sites. I understand your app is embedded under many top-level sites, but does it actually need to recognize a single user across multiple sites? If so, can you elaborate on why? (My impression is that this isn't necessarily required for an embedded SaaS application, but I'm happy to be educated otherwise.)

Alternatively - can you rely on partitioned state for the majority of your users, and only impose the top-level user interaction and Storage Access API permission prompt for the presumably-small population of users who use your application across multiple sites?

I'm also curious about the answer to a previous question of mine:

I would recommend exactly what you said: opening the embedded site once in a new tab, before asking for storage-access permission. Are there constraints that make that difficult/impossible for you?

Can you help me understand why opening a single tab (once) is an unrealistic burden for your app? I understand that the UX is no longer "seamless"/transparent, but from the browser's point of view, that can be viewed as an improvement since the user now has more control and awareness of how their data is used and flows throughout the web. When designing the Web Platform, Chrome strives to put users' needs (e.g. for control and information) above web developers' needs (e.g. for seamless UX). See https://www.w3.org/TR/design-principles/#priority-of-constituencies.

Do your users understand the permission prompts and why they might want to grant or deny permission?

Yes they do understand the prompt as we make it clear to them with a banner which asks to grant access and provides links to SASS app FAQs.

Interesting, this seems like it disagrees with a previous statement in this thread: "now the end user needs to interact with a site that they never knew they were using" (emphasis mine). Did your app recently change to show the banner to users? Or do users get a different experience depending on which browser they are using?

How do we discuss further about making the top level interactions optional or follow the same model as safari or firefox to be consistent?

I think this is the appropriate forum to discuss Chrome's behavior in this regard. CC @helenyc

@jagadeeshaby
Copy link

Thank you for the response, and yes my bad and thanks again for Correcting SASS as SaaS.

Why an application (which is always embedded) needs access to unpartitioned state?

This is for the SSO use case, where Unpartitioned cookies are set ( either via SSO Popup, Redirections - Form Post) and made available on the SaaS app domain which are required for embedded SaaS app to function.

How you ensure that the user understands what your application is and why they might want to enable/use it, given that the user never visits your site in a top-level context?

SaaS app is behind the specific Authentication and our users well aware of the SaaS app provider. As a first step , SaaS app displays a Banner which talks about why they need to provide access and links to public FAQs doc for more details.

Would be if the app is embedded under multiple top-level sites

Partially true, but it's more of Customer A using SSO enabled link to access the embedded SaaS app, consider User clicking on a SAML enabled link which does some redirections and after the successful SAML token assertion, it reaches the SaaS app domain which sets the cookie and ultimately redirects to Customer domain. Below is the simplified version of the interactions.

Step1: User clicks on login button (points to SAML SSO) on their company website, which looks like - https://saml-sso?relay-state=https://SaaS.com?destination='https://customer.com'

Step 2: SAML SSO URL redirects to relay state after the SAML token assertion (success(), which looks like https://SaaS.com -> recognizes the user and sets the cookie and redirects to destination URL - https://customer.com which gets validated against the customer registered URLs.

Step 3: https://Customer.com -> uses the Javascript library and loads the SaaS app in an iframe and at this point the SaaS app should have access to the cookie set in step 2, but it fails due to all the 3p cookie deprecations.

Step 4: to tackle the failure in Step 3 and to keep least integration changes on the customer side, we introduced RSA banner to get access to unpartitioned cookies which explains why users should click on continue and grant access ,

Step 5: user clicks continue button within the RSA banner and supposed to continue accessing the SaaS app but it fails with top level interaction error. This is where we are stuck!

Will respond to other questions in the next thread ( becoming too long)

@jagadeeshaby
Copy link

but does it actually need to recognize a single user across multiple sites?

Not necessary and this isn't our use case to consider.

Alternatively - can you rely on partitioned state for the majority of your users, and only impose the top-level user interaction and Storage Access API permission prompt for the presumably-small population of users who use your application across multiple sites?

I don't quite understand this suggestion. As SAML login flow executes directly on the top level site (not in an embedded state), having partitioned cookies doesn't mean much to the embedded App. Yes if SAML login flow could execute within the embedded context of the same top level site , then it make sense, this again has lot of challenges such as IDP needs to enable embedded login, SAML login flow include few apps which doesn't work in an embedded flow and this is potentially a multi year project to support and migrate all 100 of thousands of integrations)

why opening a single tab (once) is an unrealistic burden for your app? I understand that the UX is no longer "seamless"/transparent, but from the browser's point of view,

I'm seeing this more from a user perspective, everything we do here is to keep our users effective from day 1 on their workload ( every seconds count and billed), adding additional burden of RSA banner, native RSA popup and now additional browser popup is adding more churn to the whole workload. What we have seen so far is our customers hate browser popups and lot of our customers have popups disabled by default.

that can be viewed as an improvement since the user now has more control and awareness of how their data

We need find a balance here to optimize the experience and categorize the type of apps and collect other type of signals such as SSO enabled, some sort of a token etc to avoid putting burden on the users to satisfy some good to have rules.

were there any obvious reasons why firefox/safari doesn't have this restriction (i believe they work backwards from customers and learnt their ways)?

Interesting, this seems like it disagrees with a previous statement in this thread: "now the end user needs to interact with a site that they never knew they were using" (emphasis mine). Did your app recently change to show the banner to users? Or do users get a different experience depending on which browser they are using?

Yup as explained before, this is a hard call we took to degrade the experience by introducing the another layer with a RSA banner ( just for gaining 3p cookie access), We created this banner as a whole page hosted on the same SaaS app domain and we made this configurable in terms of theme and message so that our customers can show the messages and theme it depending on their users behavior.

Users will always have a same experience across the browser depending on whether the RSA API resolves in permission grant or Deny. in case of Granted , we directly take users to page where they continue their workload else we show the banner where they click continue ( explicit interaction) which then may/may not show the native RSA popup and takes users to desired screen.

@cfredric
Copy link
Owner

Hi, thanks for the additional details!

This is for the SSO use case, where Unpartitioned cookies are set ( either via SSO Popup, Redirections - Form Post) and made available on the SaaS app domain which are required for embedded SaaS app to function.

This means that the user must visit the SSO site (== the SaaS site) in a top-level context (either as a popup, or via a redirect), right? (I think the example URL you give in step 2 below confirms that the user does visit saas.com in a top-level context.) So it sounds like the user has visited your site (which set an unpartitioned cookie), but they haven't necessarily interacted with your site in a top-level context. Am I understanding correctly?

If so, then this is an area Chrome is still thinking about, looking for possible ways to ease/reshape this requirement while still protecting our users from trackers and abuse. The challenge is that this pattern looks identical to bounce tracking, which Chrome is working to mitigate.

If you have suggestions for how Chrome might be able to distinguish your usage from typical bounce tracking on the web, I'd love to hear them! Alternatively, if you can add a step where your user interacts with the SSO domain during the redirect (e.g.), that would also resolve this from a technical standpoint.

@jagadeeshaby
Copy link

So it sounds like the user has visited your site (which set an unpartitioned cookie), but they haven't necessarily interacted with your site in a top-level context. Am I understanding correctly?

Yes that's partially true, it may also happen that customers doing all of these in an hidden iframe as well

@jagadeeshaby
Copy link

! Alternatively, if you can add a step where your user interacts with the SSO domain during the redirect (e.g.), that would also resolve this from a technical standpoint.

i think the challenge here is , now user has to perform 3 additional clicks and a popup hassle. one Click within the popup , and another within the embedded banner and one more with the native browser popup. honestly we don't want to put this as a recommendation as there are 3 potential areas where our users might get stuck and could result in completely disrupting the work load and hence at the moment our go to option is to scrap all the RSA work and tell customer to use Enterprise policies and enable deprecation trial ( third party) as a alternate options to buy some time and focus on building long term auth solution which involves multi year dev effort and migration efforts for customers.

Whole effort for us to invest on RSA is to provide some consistent , safe options for few quarters till we build a long term path for them, but with all of this complication it doesn't sound worth investing more on this route

@jagadeeshaby
Copy link

jagadeeshaby commented Nov 16, 2023

if you have suggestions for how Chrome might be able to distinguish your usage from typical bounce tracking on the web, I'd love to hear them!

To me, it sounds like we should evaluate and learn from what Firefox is doing here, they seem to have solved this challenge and follow the same model if possible, our other option for customers now is to say start using Firefox to gain more efficiency as it involves less clicks.

@tzhao-symphony
Copy link

Hi,

I am hijacking this issue as it seems to be very similar to my own use case (Let me know if it's not appropriate and I will open another issue).

Context

Our application can be embedded on various partner websites with 2 login processes

  1. login directly from the iframe (if the user has an SSO that supports it)
  2. login from popup (as mentioned before the popup loads our application at top level but then automatically redirects the user to the SSO, and once the login is done, it goes back to our login page and programatically closes => so no top level user interaction)

We have 3 main scenarios:

  • the end user uses the application at top level, but this will most often be through a desktop application (the webapp wrapped in an electron container). So the user will likely never (or very rarely) have top level interaction in the browser.
  • the 2 embedded scenarios that I want to focus on:
    • Scenario 1: the partner top level website is an admin of the end users of our application => the same SSO is used for the partner website and our application
    • Scenario 2: the partner top level website and our application have common "third party" users and integrates us as a widget for them

Scenario 1

The partner could have a seamless integration:

  1. the user logs in on their website
  2. our application is opened in a hidden iframe and will be logged in right away thanks to the SSO done in step 1
  3. then our application can load, warm up and once ready send notifications from the background. The user would only need to show the iframe if they are interested by the notifications or actually need to use our app (and it would be instantly operational since the application loaded in the background).

With 3P cookie phase out, we will have to use Partitioned cookies to reproduce the same user experience. The main downside is that the user won't be automatically logged in if he encounters our application embedded on a different partner website or if he opens our application at top level.

Scenario 2

At the moment, if the user is logged in on our side (unpartitioned cookie), the application can directly be loaded in the background. And if he isn't, he could go through a login popup (without any top level user interaction since the user will only interact with his SSO in the popup).

With 3P cookie phase out, from my understanding, this is going to be more troublesome, and authentication will require the following steps:

  1. check if storage access is granted from the iframe
  2. if so skip to step 4. If not, open a disclaimer in a 1P popup that requires user interaction
  3. then the iframe needs to make the user click on a button to request storage access, and eventually accept the Chrome prompt
  4. the authentication check is performed and either starts the application if the user already has unpartitioned cookies or proceed with the popup login flow

Discussion

The solution we currently consider

At the moment CHIPS specification is not very clear to me, but from my testing (Chrome Version 120.0.6099.18 (Official Build) beta (x86_64)):

  • Chrome supports unpartitioned and partitioned cookies with the same name, domain and path (though as of now 1P Partitioned cookies are not displayed in the DevTools). While it's discouraged (Servers SHOULD NOT include more than one Set-Cookie header field in the same response with the same cookie-name), both can be set from the same response headers => will this always be true?
  • When Storage Access is granted, the embed can read and write unpartitioned cookies
  • 1P Partitioned cookies are not accessible from iframes even if storage access was granted

To tackle the 2 scenarios described above, we would need both a partitioned cookie solution as well as an unpartitioned cookie one.
As much as possible, we would like to keep the backend authentication api consistent across both scenarios, so my thought was to set both a partitioned and unpartitioned version of the various session/anti-csrf cookies. Do you foresee any issue with that?

What would enhance user/dev experience

Even then, the user experience is not ideal, and the use of 2 cookies feels messy.

Here are a few suggestions that could enhance the overall experience without costing too much in terms of privacy (in my opinion at least):

  • Either partition 3P cookies by default (I think this is the current behaviour of Firefox, it's probably less disruptive for most embeds) or allow 3P iframes to access 1P Partitioned cookies if the user grants storage access. Currently, from my understanding, an iframe with storage access will behave pretty much like if it was 1P (access to unpartitioned storage). Then why not applying the same logic for 1P partition storage? That combined with Storage Access would enable developers to only set unpartioned or partitioned cookies on both top level and embeds.
  • Allow users to select for how long they want to grant storage access, possibly with an "Always" option a bit like for popups. If the prompt is only a one-off, then it would feel way better in terms of user experience.
  • Allow the embed to know if it is eligible to requestStorageAccess (notably, does it require the user to make a top level interaction?), or as @jagadeeshaby mentioned, totally remove the need of top level interaction since an interaction is already required in the iframe. This seems to be how Firefox implemented it.

Questions

  • Is there a way to clear the history of "top level interaction"? It would be great for testing purpose.
    _ What is the future of requestStorageAccessFor? Is it planned to be supported outside Related Website Sets?

@cfredric
Copy link
Owner

Hi @tzhao-symphony,

Agreed, this does sound like a similar problem. Again, I'd love to have your suggestions on how the browser can distinguish the "seamless" flow you describe from the silent cross-site tracking that is possible via bounce tracking and third-party cookies today, in order to protect users from tracking while enabling your applications to keep working in the more-private web of the future. And I'd love to hear why engaging with the user in a top-level context (once, not every visit!) is not feasible as part of the SSO flow, as well.

With regard to your questions specifically:

Chrome supports unpartitioned and partitioned cookies with the same name, domain and path (though as of now 1P Partitioned cookies are not displayed in the DevTools). While it's discouraged (Servers SHOULD NOT include more than one Set-Cookie header field in the same response with the same cookie-name), both can be set from the same response headers => will this always be true?

I don't work on CHIPS, so I don't know the answer to that. I suggest looking through https://github.com/privacycg/CHIPS/issues and asking this question there, if it isn't addressed yet.

As much as possible, we would like to keep the backend authentication api consistent across both scenarios, so my thought was to set both a partitioned and unpartitioned version of the various session/anti-csrf cookies. Do you foresee any issue with that?

I recommend asking this on the CHIPS repository as well. My gut instinct would be to try to deduplicate data that's shared between partitioned/unpartitioned cookies (it's impossible for things to get out-of-sync if there's only one thing to update), but I haven't thought through things like partitioned anti-CSRF tokens.

Either partition 3P cookies by default (I think this is the current behaviour of Firefox, it's probably less disruptive for most embeds) or allow 3P iframes to access 1P Partitioned cookies if the user grants storage access. Currently, from my understanding, an iframe with storage access will behave pretty much like if it was 1P (access to unpartitioned storage). Then why not applying the same logic for 1P partition storage? That combined with Storage Access would enable developers to only set unpartioned or partitioned cookies on both top level and embeds.

In Chrome, an iframe that has obtained storage access can still access the partitioned cookies available in that context, in addition to the iframe's unpartitioned cookies. Requesting storage access via document.requestStorageAccess() doesn't take away the ability to use partitioned cookies.

Allow users to select for how long they want to grant storage access, possibly with an "Always" option a bit like for popups. If the prompt is only a one-off, then it would feel way better in terms of user experience.

This could be possible. But Chrome's current implementation already allows the prompt to be a one-off, if the user uses that embedded application on that site at least once a month. So, since the "always" option would only be useful for people who rarely use the embedded application, I'm not convinced of the benefit here.

Allow the embed to know if it is eligible to requestStorageAccess (notably, does it require the user to make a top level interaction?), or as @jagadeeshaby mentioned, totally remove the need of top level interaction since an interaction is already required in the iframe. This seems to be how Firefox implemented it.

We're still thinking about this and exploring the options here. We'd love to know what you suggest as a requirement instead of the top-level user interaction requirement, but I don't see a way to simply remove it like Firefox currently does.

(Remember that Chrome deletes cookies on top-level sites that do this kind of interaction-less redirect, to protect our users from bounce tracking as I mentioned above. So even if Chrome waived the top-level interaction requirement, the cookies would get deleted anyway, unless Chrome also relaxed its bounce tracking protections -- which I believe is unlikely, and which I don't think would be good for our users. So we need a different solution here, which I'd love your input on.)

Is there a way to clear the history of "top level interaction"? It would be great for testing purpose.

Clearing browsing history (via chrome://settings/clearBrowserData) clears the top-level interaction history.

What is the future of requestStorageAccessFor? Is it planned to be supported outside Related Website Sets?

Uncertain right now. Browser vendors are still working on some ideas in this space (e.g. https://github.com/bvandersloot-mozilla/top-level-storage-access), so Chrome is participating in those discussions right now.

@tzhao-symphony
Copy link

Hi @cfredric

The reason why we need to duplicate the cookie is that:

  • our popup login flow requires access to cookies at top level. The only current way to make this work is to set Unpartitioned cookie and use SAA in the iframe.
  • our iframe login flow requires Partitioned cookies so that we can avoid all the additional user interactions required by SAA

Now let's say a user does the following and 3p cookie are not phased out yet:

  • he goes to a partner website with popup login. Unpartitioned cookies are set.
  • After a while the session information from the cookies are obsolete.
  • He then goes to a partner website with iframe login. The backend detects the obsolete session from unpartitioned cookies. And ask the user to login. Partitioned cookies are set. However on subsequent requests, the unpartitioned cookies are still there as they are not overridden by the Partitioned cookies. So the user will be asked to login again and again.

Duplicating the cookies will ensure that both Partitioned cookies and unpartitioned cookies are always up to date whether 3p cookies are phased out or not (I am not sure the UI can detect that).

If 1p Partitioned cookies were accessible thanks to storage access, that would make the flow simpler. In a first iteration we could always set Partitioned cookies and expire Unpartitioned cookies (so that left overs from the previous backend version would be cleaned up). Are there scenarios where we don't want 1P CHIPS to be shared with a 3P embed that was granted storage access?

This could be possible. But Chrome's current implementation already allows the prompt to be a one-off, if the user uses that embedded application on that site at least once a month. So, since the "always" option would only be useful for people who rarely use the embedded application, I'm not convinced of the benefit here.

Ok I think I got mixed up between the initial requestForStorage that required top level user interaction in the past 30 days and the permission automatic renewal when the user interacts in the embed. So if a user grants access to top.com+embed.com, as long as the user interacts with the embed once every 30 days, the permission will be renewed. This is actually good news.

We're still thinking about this and exploring the options here. We'd love to know what you suggest as a requirement instead of the top-level user interaction requirement, but I don't see a way to simply remove it like Firefox currently does.

(Remember that Chrome deletes cookies on top-level sites that do this kind of interaction-less redirect, to protect our users from bounce tracking as I mentioned above. So even if Chrome waived the top-level interaction requirement, the cookies would get deleted anyway, unless Chrome also relaxed its bounce tracking protections -- which I believe is unlikely, and which I don't think would be good for our users. So we need a different solution here, which I'd love your input on.)

The user already needs a user interaction within the embed to get the prompt, which shows that he wanted to interact with the embed. Even in case of a missclick, he would then need to willingly accept the prompt. So the combination of the user interacting with the embed + accepting the prompt tends to show that the user really wanted to use and grant storage to the embedded site.
Now if there must be a top level site interaction I could see the following:

  • it would be welcomed to have an API to know whether the user can grant access to the embed right away or needs a top level interaction first
  • if there is a history of the user interacting often with the site either in an embedded context or at top level, the browser could deduce that the user trusts that particular site and remove the top-level interaction requirement as well as bounce tracking mitigations.
  • if storage access has been granted to an embed, then Bounce Tracking Mitigations could be disabled (or at least the part deleting top level cookies)
  • I don't know if this is possible, but rules might be relaxed (applies both for SAA requiring top level user interaction and Bouncing tracker mitigation) unless the sites show specific signals:
    • low user interaction (both in embedded context and top level)
    • intensive use of programmatic redirects
    • intensive use of requestAccessStorage (and in a lot of different contexts?) with a high rate of users denying storage access

@cfredric
Copy link
Owner

cfredric commented Dec 8, 2023

Hi, apologies for the slow response.

If 1p Partitioned cookies were accessible thanks to storage access, that would make the flow simpler.

IIUC when you say "1p Partitioned cookies" you mean partitioned cookies whose partition key is the same as the site that set the cookie? I.e., partitioned cookies that were set by the top-level context itself?

If so, I don't see the difference between using the site's unpartitioned cookies and using the site's 1P partitioned cookies. Both kinds of cookies can be set in a first-party context, and the Storage Access API already makes unpartitioned cookies fully available in cross-site iframe contexts. (1P partitioned cookies are currently intentionally unavailable in cross-site iframes.)

If your application gets confused by obsolete unpartitioned cookies, you can just update/delete the unpartitioned cookies when you set the partitioned cookies. Am I missing something?

The user already needs a user interaction within the embed to get the prompt, which shows that he wanted to interact with the embed.

I think you're assuming that the top-level page and embedded frame are benevolent. Malicious actors do things like clickjacking attacks, which means that statements like "the user clicked on this frame intentionally" are not universally true. Chrome must assume that there are malicious sites that will try to misuse whatever features we provide.

Even in case of a missclick, he would then need to willingly accept the prompt.

Part of Chrome's goal is abuse prevention and avoiding prompt fatigue. It should not be easy to trigger a prompt for the user, since that's a disruptive experience and forces the user to make a decision. So we want to restrict that capability so that prompts can only be created by sites which the user is familiar with (and can therefore make an informed decision about), e.g. sites that the user has visited recently.

Now if there must be a top level site interaction I could see the following: ...

Thanks for these suggestions! Your first bullet is related to discussion happening in privacycg/storage-access#60. I agree with my colleague johannhof, there's potential to improve the UX here.

Your second bullet is an interesting thought, but I'm not sure it's a good idea. It would make the behavior of requestStorageAccess() less predictable for web developers, which I'd like to avoid if possible. (I realize that the top level user interaction requirement already makes the API unpredictable to some extent; I don't want to make the situation worse.)

Your third bullet is related to privacycg/nav-tracking-mitigations#65; feel free to chime in there.

Your fourth bullet is also a potential feature request for the bounce tracking effort; I think it'd be better to discuss there with the folks who own that repository, rather than here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants