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

feat: Technical review — Related website sets docs #30500

Closed
wants to merge 33 commits into from

Conversation

chrisdavidmills
Copy link
Contributor

@chrisdavidmills chrisdavidmills commented Nov 24, 2023

Note: This technical review is now completed and approved. For the follow-on editorial review, see #30654.


Description

Related website sets is a part of Chrome's privacy sandbox project. It provides progressive enhancement for The Storage Access API, allowing the definition of a set of related, trusted sites that can receive automatic permission to access third party cookies originating from the set.

This PR aims to do the following:

  • Write a Related website sets page, nested under the Storage Access API page.
  • Document the Chrome-only Document.requestStorageAccessFor() method and add mentions and links in appropriate places
  • Update the main Storage Access API page to mention the above and provide an up-to-date picture of the API
  • Update the Using the Storage Access API page to include details of the above.
  • Update mentions of "first-party sets" to "related website sets"
  • Update permissions API information to include the top-level-storage-access permission feature name specific to requestStorageAccessFor(), and make sure the storage-access feature is marked as supported in Fx.

Notes/questions

  • I updated all of the docs to talk about third-party cookies rather than unpartitioned cookies, as the former is much more understandable and more relevant generally to what we mean, although not as strictly correct. I did add a section to explain unpartitioned versus partitioned cookies, and that generally we implicitly mean unpartitioned when we are taking about cookie access with the SAA.
  • The relevant compat data is being updated in Update Storage Access API data browser-compat-data#21336. Once that is merged, I have a few extra updates to add:
    • Update api.Document.requestStorageAccessFor to mention that the sites involved have to be in the same RWS for it to work
    • Add the top-level-storage-access feature name to api.Permissions
    • Optionally add a separate data point for RWS, although I'm not really where this would live inside the BCD repo.
  • I noticed that in the SAA spec, it talks about Permissions API and Permissions-Policy integration, with a feature name of storage-access for both. However, on the requestStorageAccessFor() spec it only talks about Permissions API integration, with a feature name of top-level-storage-access. Does this mean that requestStorageAccessFor() is not controlled by Permissions-Policy, or does it mean that it is, but it is controlled by storage-access permissions policies, like the rest of the SAA? I've currently written my docs as if the former is true, but I cna easily update this if it turns out to be wrong.

Motivation

Additional details

Related issues and pull requests

@chrisdavidmills chrisdavidmills requested review from a team as code owners November 24, 2023 13:23
@chrisdavidmills chrisdavidmills requested review from sideshowbarker, teoli2003 and dipikabh and removed request for a team November 24, 2023 13:23
@github-actions github-actions bot added Content:WebAPI Web API docs Content:Other Any docs not covered by another "Content:" label Content:HTTP HTTP docs Content:Security Security docs labels Nov 24, 2023
@chrisdavidmills chrisdavidmills marked this pull request as draft November 24, 2023 13:23
Copy link
Contributor

github-actions bot commented Nov 24, 2023

Preview URLs (11 pages)
External URLs (18)

URL: /en-US/docs/Web/HTTP/Cookies
Title: Using HTTP cookies


URL: /en-US/docs/Web/Privacy/Partitioned_cookies
Title: Cookies Having Independent Partitioned State (CHIPS)


URL: /en-US/docs/Web/API/Document/requestStorageAccessFor
Title: Document: requestStorageAccessFor() method


URL: /en-US/docs/Web/API/Permissions_API
Title: Permissions API


URL: /en-US/docs/Web/API/Storage_Access_API
Title: Storage Access API


URL: /en-US/docs/Web/API/Storage_Access_API/Related_website_sets
Title: Related Website Sets

(comment last updated: 2023-11-30 08:05:10)

@chrisdavidmills chrisdavidmills marked this pull request as ready for review November 27, 2023 10:06
@chrisdavidmills chrisdavidmills changed the title Related website sets docs feat: Technical review — Related website sets docs Nov 27, 2023
files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved
files/en-us/web/http/cookies/index.md Outdated Show resolved Hide resolved
files/en-us/web/privacy/index.md Outdated Show resolved Hide resolved
files/en-us/web/security/index.md Outdated Show resolved Hide resolved
files/en-us/web/privacy/index.md Outdated Show resolved Hide resolved
@chrisdavidmills
Copy link
Contributor Author

Does this mean that requestStorageAccessFor() is not controlled by Permissions-Policy, or does it mean that it is, but it is controlled by storage-access permissions policies, like the rest of the SAA?

The latter - it's controlled by the SAA permission policy in Chrome.

OK, great. I've added the necessary Permissions Policy info back into the requestStorageAccessFor() ref page.

files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved

> **Note:** The Chrome-only [related website sets](/en-US/docs/Web/API/Storage_Access_API/Related_website_sets) feature can be considered a progressive enhancement mechanism that works alongside the Storage Access API — supporting browsers grant default third-party cookie access between websites in the same set. This means not having to go through the usual user permission prompt workflow described above, meaning a more user-friendly experience for users of sites in the set.

## Requesting storage access on behalf of a related domain
Copy link
Contributor

@tunetheweb tunetheweb Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this title is incorrect. Or at least misleading.

AFAIK requestStorageAccess also allows use of related domains to skip the prompt in Chromium-based browsers. So it too can benefit from related domains, but this section only discusses requestStorageAccessFor.

What requestStorageAccessFor specifically allows is access at the top level document (i.e. not in embedded iframes) for images or other such directly embedded content. AFAIK that's only implemented for related domains (rather than also with prompts) so that's the ONLY way with this API at present.

So I think this title should be something like:

Suggested change
## Requesting storage access on behalf of a related domain
## Requesting storage access for resources in the top-level document

Or somethign like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading descriptions of the method in the spec and DCC, it sounds like both of our suggestions are potentially misleading.

It sounds like you are saying here that requestStorageAccessFor() is only for requesting storage access for directly embedded resources that could set cookies, like images in <img> elements, and not resources embedded in <iframe>s. But the above links seem to suggest that it can do both.

I'm therefore adding text to the SAA landing pages and method page to make this clear, and changing the heading to Requesting storage access from the top-level site on behalf of embedded resources. Does that sound OK, or have I got the wrong end of the stick here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That title works for me. Maybe @cfredric can review too just to be sure?

My main concern was the original title suggested you had to use requestStorageAccessFor when working with related domains but if I understand correctly you can continue to use requestStorageAccess if it's just for iframed content (and use the fact that they are related domains to avoid the prompt in supporting browsers like Chrome).

I do agree that it's odd that the d.c.c. link suggests requestStorageAccessFor is for "cross-site images or script tags requiring cookies" and the spec includes iframes ("embedded resources such as iframes, scripts, or images") too which seems a little inconsistent. But maybe d.c.c. wanted to avoid the confusion with Storage Access API so kept it to the simpler use cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up adding a description in the requestStorageAccessFor() method page and the "Using" guide along these lines:

requestStorageAccessFor() is intended to address challenges in adopting the Storage Access API on top-level sites that use cross-site images or scripts requiring cookies. It can enable third-party cookie access for cross-site resources embedded in {{htmlelement("iframe")}}s, and directly embedded e.g. via {{htmlelement("img")}}s or {{htmlelement("script")}} elements.

As I understand it, the method is for top-level pages to request storage access for their embedded content, whereas regular requestStorageAccess() has to be called from inside the embedded content, to request access for itself. In which case, I think the descriptions are now OK.

But, let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That title works for me too.

Apologies for the confusion around the DCC page and the spec. My summary of things (in Chrome) would be:

  • requestStorageAccess() skips the prompt if both sites (top-level and embedded) are in the same RWS; otherwise may show a prompt. Expected to be called in an embedded iframe. Intended for cross-site iframes that have their own logic and resources and need cookies.
  • requestStorageAccessFor(origin) resolves and grants permission if both sites (the top-level and origin) are in the same RWS; otherwise rejects. Never shows a prompt. Must be called by the top-level document. Intended for cross-site resources (not necessarily iframes) that need cookies, but can't call requestStorageAccess() themselves.

Specifically about rSAFor and iframes: the "top-level-storage-access" permission only helps for resources that are loaded by the top-level document. I.e., any cross-site subresources that are loaded within an embedded iframe won't benefit; that iframe should use requestStorageAccess() instead. However, if the iframe source itself is cross-site and can only be loaded by authorized users (i.e. the iframe's load needs cookies), then the top-level document can use requestStorageAccessFor(origin) and the load the iframe with CORS to attach the cross-site cookies to the request.


I think the requestStorageAccessFor spec is in need of some updates as things have changed in the Storage Access API in the last few months; I'll put that on my team's todo list.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me! I thought it might be for the iframe needing access to even load case.

Copy link
Contributor

@cfredric cfredric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - largely looking good to me.

files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved
Copy link
Contributor

@tunetheweb tunetheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@cfredric cfredric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Chris!

files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved
files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved
files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved

In the above code, we call `navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://example.com'})` To discover if the user will be prompted or if storage access has already been granted to the specified origin.

- If the permission status is `"granted"` we call `document.requestStorageAccessFor('https://example.com')`, which should succeed without a user gesture.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- If the permission status is `"granted"` we call `document.requestStorageAccessFor('https://example.com')`, which should succeed without a user gesture.
- If the permission status is `"granted"`, we can immediately use cross-site cookies in CORS-enabled requests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? For SAA we still need to call requestStorageAccess if the page is the granted state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I wrote what I meant to here :)

For requestStorageAccess(), the reason Chrome requires the iframe to always call rSA (even if permission has already been granted) is to protect the iframe from a CSRF attack. The iframe has to actively choose to include its cross-site cookies in requests, even if some other frame (elsewhere on the page, or on some other page within the last month) has already gotten the requisite permission. The call to rSA is treated as an active "opt-in" that indicates this specific iframe is ok with including cross-site cookies in its fetches.

For requestStorageAccessFor(origin), the "active opt-in" from the 3p site comes in the form of the server's CORS support. If the server doesn't want to honor the cross-site requests, it can use CORS headers (or lack thereof) to protect itself. (Regarding an opt-in from the 1p site, that's less important from a security perspective, but it's still there. It comes in the form of ensuring the top-level document's subresource request uses CORS mode. Without CORS mode, the "top-level-storage-access" doesn't apply, so cross-site cookies wouldn't be attached to the request.)

Copy link
Contributor

@tunetheweb tunetheweb Nov 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. The fun of similar, but different, APIs! I presume requestStorageAccessFor(origin) is only needed for the first usage to set that to granted? After that it remembers it for the period (30 days?) and doesn't require re-requesting?

In which case, @chrisdavidmills on the line above you say:

In the above code, we call navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://example.com'}) To discover if the user will be prompted or if storage access has already been granted to the specified origin.

But there are no prompts with this API if I understand correctly, so I think this should be:

In the above code, we call navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://example.com'}) to discover if the page has previously called requestStorageAccessFor() and thereby granted permission, of if this call needs to be made to grant this access.

Or something like that.

Is that correct @cfredric ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tunetheweb Yup, I agree with that rephrasing. (And you're correct about the first usage and the permission's lifetime (30 days))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've ended up rehrasing this again slightly this morning. The final text I came up with was:

In the above code, we call navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://example.com'}) to discover if the origin has previously been granted permission, or if cookie access still needs to be requested.

  • If the permission status is "granted" we can just start using cookies; requestStorageAccessFor() was already called so there is no need to call it again.
  • If the permission status is "prompt" we need to call document.requestStorageAccessFor('https://example.com') call from within a user gesture, such as a button click.

files/en-us/web/api/storage_access_api/using/index.md Outdated Show resolved Hide resolved
@chrisdavidmills
Copy link
Contributor Author

@cfredric In light of latest comments and now understanding behavior better, I tinkered with some of the wording a bit more ;-)

Copy link
Contributor

@cfredric cfredric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thanks for all the updates!

@chrisdavidmills
Copy link
Contributor Author

@cfredric @tunetheweb OK, looks like you are both happy with the content's technical accuracy. Thanks a lot for the review work.

The next stage is to close this PR, and open a new one based on the same branch to contain the editorial review. If you find anything else that desparately needs changing, you can always bring it up in the editorial PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:HTTP HTTP docs Content:Other Any docs not covered by another "Content:" label Content:Security Security docs Content:WebAPI Web API docs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants