-
Notifications
You must be signed in to change notification settings - Fork 56
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
Add permissions.requestSiteAccess() API proposal #529
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this!
|
||
Specifying URL patterns instead of tabId or documentId in `permissions.requestSiteAccess`. We decided against that because: | ||
- This is designed to be a highly-contextual signal -- the extension should do it only if they have strong believe they will provide value to the user on the given page | ||
- We do not want extensions to simply show a request on every page, and specifying a list of patterns would lend itself to that behavior |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patterns vs no patterns does not prevent the extension from calling this API for every tab / page. So I'm not sure this is true.
But I agree, taking a tabId
/ documentId
is best (other than my caveat about how does the extension know what tab it needs without access.)
|
||
#### Use Cases | ||
|
||
An extension requested access to a site but the user withheld its access and forgot about it. Extension wants to signal it needs site access to execute. For example, “shopping” extension wants to show site access when user navigates to “amazon.com” and access was withheld. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If an extension does not have access, how does it know what tabId
is needed to pass to this API? They can't see the url
or title
on the tab object if they don't have access (at least in Safari, where those are empty unless you have host permissions. That might be different in Chrome where only the tabs
permission is needed?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's an interesting question. In Chrome the tabs
permission is sufficient to access the URL. In Safari, I wonder if there are other situations where the extension realises it might be useful on a page - based on a shortcut running perhaps? - and the extension could request access. I know Safari has a lot of behaviour to automatically prompt the user though so perhaps not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of interest, does the tabs
permission do anything in Safari? Despite the name it isn't needed to call (I think all) tabs APIs in Chrome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oliverdunk Yes, tabs
does signal to us that the extension implicitly wants access to all websites, so they don't need *://*/*
in the host_permissions
to get our implicit permission request dialogs when doing tabs
actions like query()
, executeScript()
, etc.
At what point would an extension want to use this? As @xeenon pointed out, how do I know which tab to target if I don't know their URL? Is this API only useful when the user is already interacting with the extension via sidePanel? That's the only scenario I can think of where the user doesn't have activeTab but the extension would probably want access. Or maybe is this API meant to preserve access to a tab with a temporary activeTab permission? I worked on a related UI before (webext-permission-toggle) so I wonder how I could use this. |
- When accepted, grants always access to the site’s origin | ||
- Resets the request on cross-origin navigation | ||
|
||
#### Use Cases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this is a confusing API to developers, and it would be better if there were more concrete use cases. What value can this API bring to extensions? Is there any relevant data for browsers' "site access" function? Are users satisfied with "site access" function, or are users encountering any problems? The above questions are just to avoid developing an API that no one uses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can share a bit of extra context here. We are still looking at possible permission UI changes like the ones mentioned at I/O. This doesn't include changing any defaults, but we do still expect more users to experiment with different access settings. It feels like putting APIs in place first is better than adding them retrospectively, which would imply a gap between when the UI launches and when APIs to adapt to them are available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like it belongs in a manifest rather than as an API. I think extensions fall into these categories:
- on demand: just take an action when invoked (
activeTab
) - for specific websites: think "Reddit Enhancement Suite" or "Refined GitHub", that have a pre-set list of domains to run on
- for all websites: think content blockers, Grammarly
Between these there are a couple more cases:
- A: pre-set list, but more can be added
- B: all websites, but some can be disabled
"A" can be achieved via .request()
when the user desires; "B" is covered by Chrome's current UI.
I'm not sure where requestSiteAccess
falls on this spectrum.
Once I specify optional_host_permissions: all_urls
, the browser should already:
- Show "This extension is available on this website"
- Allow toggling the permission
In your proposed new UI, it looks like this could be covered already: just show the extension on the list, but disabled.
As a user, I wish that I had a way to enable the type A on more websites in a consistent way.
As a developer, I wish I didn't have to manually handle content script registration and permission requests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely agree that not having to manually handle this would be nice and think that'd be interesting to experiment with. For some of your cases I agree that might work.
I do think there is another case to the ones you mentioned. Consider a shopping extension that can only offer coupons on certain sites, and it downloads this list remotely. It specifies <all_urls>
, so can run everywhere, but a user explicitly revokes its access from all pages. It would be nice if the extension had a way to less intrusively flag "I checked my list and I can run here, you might want to add me back on this domain".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if the extension had a way to less intrusively flag "I checked my list and I can run here, you might want to add me back on this domain".
Why isn't the list in the manifest?
But still from a manifest standpoint, what is the point of host_permissions
if they can be disabled? It sounds like we need:
- compatible host list: all_urls
- suggested host list: eBay, amazon, etc
To fit into this proposal:
- compatible host list:
host_permissions
- suggested host lists: a new
preferred_hosts
The drawback is that extension developers have to submit a new extension to update the list, but the advantages are that the browser has total control on how/when to show it, and the developer doesn't have to deal with issues like "when and how often can I requestSiteAccess
?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, the wording may have been slightly confusing there. It would often be used to grant access to content scripts. The API itself would definitely be available in background contexts.
An example use case in Chrome would be something like this:
- An extension requests <all_urls> in host_permissions
- The user changes the site access to "on click" or "on specific sites" (note that they can do this even if the host permissions weren't specified as optional)
- In the background, the extension realises it can inject a useful content script (for example, it notices a tabs.onUpdated event and the tab has a URL it has special logic for)
- The extension would then prompt for access to that tab ID
Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's take a step back and see current behavior (updated proposal Background
section too)
Please, feel free to correct me on other browsers behavior since I'm not fully familiar!
- An extension can request host permissions. At installation, they are granted (Chrome, Firefox) or withheld (Safari) by default
- An extension can request optional host permissions, that can be granted after a user action
- In Chrome and Safari, extension site access can be withheld
- In Chrome, withholding an extension site access means the extension is set to run "on click". When the extension is clicked (either the pinned action or through the extensions menu) it gets access to run on the origin top frame until cross-origin navigation.
permissions.request()
allows an extension to request site access after a user action
Let's have an example now (similar to Oliver's on previous comment). In Chrome:
- An extension requests
<all_urls>
in host_permissions - User navigates to site.com
- The user changes the
site.com
site access to "on click" - User navigates to
site.com/useful
- In the background, the extension realizes it can inject a useful content script on
site.com/useful
User can realize the extension wants to run by opening the extensions menu. However, there is no way for the extension to say "I really want to run on this specific page" without user action. Yes, it could work with a declarative list. However, we have listed our reason why we prefer not to (updated proposal's Other Alternatives Considered
section)
@hanguokai
As for the issue of extension requesting host_permissions that are not in the tab top frame origin. At least on Chrome, this is the actual behavior of granting site access to an extension. Granting site access to a host (either by activeTab or allowing site access "on site" / "on all sites") grants only to that host, meaning the tab's top frame origin. This new API is following the same, so it wouldn't fix that issue.
it asks for further host permissions or it asks for permanent permission to the current context
Extension cannot ask further host permissions. It would ask for host_permissions that were withheld by the user
As a user, if a the browser asks for a permission for a third domain, I don’t think I'd accept without further explanation, especially if I explicitly blocked the extension on that domain before.
Browser cannot ask permission for a third domain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your further explanation. Now I have a clearer understanding of the intent of this API. But in my opinion, this is still a controversial API.
How to use this API
- In the background, the extension realizes it can inject a useful content script on site.com/useful
Can you further explain what developers are supposed to do here?
Because this API is bound to browser tabs, I think developers need to use tabs.onCreated/onUpdated/onReplaced
events to detect tab's top frame changes, and must need the "tabs" permission to get tab.url
and/or tab.title
. In these events, developers are facing two possible situations: 1. already has the host permission and already inject content scripts 2. don't has the host permission and no injected content scripts. Therefore, developers first need to determine whether has the host permission. If no host permission, at this stage, extensions only know tab's url and title, and don't know the page's content since it has not inject a content script. At this point, developers can only rely on these two pieces of information (url and title) to determine whether to apply for the site permission, i.e. call permissions.requestSiteAccess()
.
Here, without knowing the content of the page, it may be difficult for developers to determine whether it strongly requires the site access. In the case of shopping, I only know the URL and title, I may can't know what product is being sold on the current page, so I can't tell if there is a coupon for that product.
The model itself
In Chrome, withholding an extension site access means the extension is set to run "on click". When the extension is clicked (either the pinned action or through the extensions menu) it gets access to run on the origin top frame until cross-origin navigation.
I rarely use this feature. I also rarely hear users use this feature. So I want to repeat the question I asked at the very beginning: Is there any relevant data about this function? Are users satisfied with this function, or are users encountering any problems at present?
I think the model itself is flawed, it only fits a small subset of real use cases, and a lot of use cases (perhaps 50% or more) don't fit the model (We have already given examples before).
Experiment with this API without standardization
In my opinion, there are still doubts about the actual value of this API for developers and users. I think Chrome can first experiment with this API (for a year) to see the actual effect. Tell developers explicitly that this is an experimental API and that it may be modified incompatibly or even removed in the future. This way, an experimental API does not require the agreement from other browsers. For example, let developers apply an Origin Trial token to experiment this API (see #454).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to use this API
Correct, those are the two scenarios although I would phrase them slightly differently (to match terminology):
a. Extension request host permission and it's granted by the user. Extension has injected scripts
b. Extension request host permission and it's withheld by the user. Extension ha no injected scripts
On scenario a., you are right. Extension does not know the page content. Extension has access to:
permissions.getAll()
returns the active permissions. Extension can know if a host permission is not in the returned permissions origintabs.get()
returns tab URL, title, ...- other APIs like
windows.getCurrent()
to get more information
Here, without knowing the content of the page, it may be difficult for developers to determine whether it strongly requires the site access. In the case of shopping, I only know the URL and title, I may can't know what product is being sold on the current page, so I can't tell if there is a coupon for that product.
Currently, the only way for developers to determine whether it requires site access is to check if it has active permission for the page. This provides a way to show a visible request when this happens.
Yes, it's probably not sufficient to know given a tab id / document id that the extension "strongly needs access to the site". However, what would be another way to determine that? (if host permissions are withheld, extension doesn't have access to the page). By looking at document id / tab id, extension can get more information than if it just gave a declarative list of URLs (as explained in previous point).
The model itself
I rarely use this feature. I also rarely hear users use this feature.
User withholding host permissions is not a common practice today. However, we expect that to change in the future because:
- Browsers are exploring withholding permissions at installation. Safari already does that, and I believe Firefox is exploring that in MV3. Chrome is exploring that too
- At least in Chrome, it will be more accessible for the user to withhold host permission in the extensions menu (that means, setting the extension to run "on click")
Is there any relevant data about this function? Are users satisfied with this function, or are users encountering any problems at present?
We did user research on showing a request in the Chrome toolbar every time a extension wants site access to a withhold host permission. Users found it to be too nosy, and not always helpful. However, they mentioned that the request is relevant then it provides value.
Thus, we drafted this proposal to show the request only when the extension requests to show it. Yes, it can be always but at least it gives the option to the extension to have it be more relevant and the browser to better control it.
I think the model itself is flawed, it only fits a small subset of real use cases, and a lot of use cases (perhaps 50% or more) don't fit the model (We have already given examples before).
Agree, the real use cases subset is small now. However, we expect this to increase as mentioned on the first point on this section.
Experiment with this API without standardization
Do other browsers see a potential path forward for this API? Otherwise, Chrome can continue without standardization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proposal was updated to include url so it can fit other browsers. Browser can add requirements on which parameters must be provided. For example, Chrome will require tabId
or documentId
to be provided and url
can be added on top of that.
|
||
### Other Alternatives Considered | ||
|
||
Specifying URL patterns instead of tabId or documentId in `permissions.requestSiteAccess`. We decided against that because: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL pattern is a reasonable way to tell the browser which websites an extension can work for. And extensions don't need to get Tab's URL. We should not deny a reasonable approach. The browser can decide how to prompt the user with this hint(URL pattern). BTW, a specific host permission (not too broad pattern like <all_urls>) is already a hint.
I want to make a slightly off-topic comment expanding on what @hanguokai said earlier about host permissions not being bound to Tabs. Sorry for being off-topic, but I think it's worth increasing awareness on this, and whether it's worth a fix. @oliverdunk or @dotproto - I'd be happy for this to be spun off into a separate issue, but I can only describe the problem and not the solution. There's a confusing situation where an extension would ideally have only "activeTab" permissions ('When You Click the Extension' in the Chrome UI), but needs broad The problem happens for an extension that runs on the active-tab when the user clicks the extension button. The extension gains I ran into this issue when writing an extension that fetched and processed images on the current webpage. @dotproto and I had a Chromium Extensions chat about this back in December 2021. I submitted a Chromium feature request back in July 2022 to allow CORS-free access to dom image elements. However, I'm now thinking this issue should be handled at the CORS level when fetching a resource. Maybe "activeTab" permission could be relaxed slightly to allow extension access to all origins used in rendering a page. Or at least GET read access. In the previous chat, @dotproto said this wasn't done, as "if a user invokes the extension on a page with, say, social media sharing widgets, it's not clear that the user also wants to grant the extension access to all of those social media sites as well". However, if you're balancing this against the current approach of broad Sorry for being off-topic @EmiliaPaz - I thought it was worth adding this comment, given we're covering |
Thanks for raising this. I think there is some overlap since this API will also only grant access to the top-level site's origin. The reasoning for this is very similar to everything you mentioned with the behavior of There is actually some precedence for granting more than the current origin with All of that said - the general opinion last time I discussed this within Chrome (which I am inclined to agree with) is that we should keep looking for a good solution, but automatically granting access to all origins associated with a tab isn't it. It may reduce the use of widely scoped host permissions, but at the cost of making it harder for users to understand what an extension can do. It doesn't feel like it meaningfully improves the situation unfortunately and it would be better to keep thinking about this. |
@oliverdunk many thanks for the considered response. I do wonder if the CORS issue I described is narrower that it looks, and predominately applies to images. If so, the solution to this might be image-specific (like my chrome.dom.createDomImageBitmap API proposal), rather than a 'grant wider origin access' solution, and so fix 90+% of issues. My detailed knowledge of CORS has faded, but if I recollect correctly:
In which case, if extensions are primarily focussed on processing a rendered webpage and associated loaded resources, then the issue becomes image-specific. |
For your use case it definitely sounds like something narrower in scope might work, though I do share the concerns about doing something cross-origin in nature within a content script. Feel free to ping on the issue and we can keep discussing there 😁 |
- Update Background section to take into account different browser's behavior - Update Other Alternatives Considered section to explain in better detailed why Chrome is not supportive of declarative urls
Proposal has been updated so it can fit every browsers model by adding a url option parameter, with this requirements: - In Chrome, we can require tab ID or document ID, but not `url`. - In Safari, they can require `url`, but not `tabId` or `documentId`. - If both are provided, they'll both be respected. It also adds a method to remove the request and specifies when the methods resolve
- Change name to `permissions.addSiteAccessRequest()` - Fix API comments
In the public WECG meeting (see _minutes/2024-02-29-wecg.md), we decided to move forward with The only decision left is whether the parameters We (Chrome) think option a) is better because it maintains the same signature for all browsers. For example:
would be a valid API call and behave the same in every browser. Option b. means the same signature could not be used across browsers and there would need to be some try/catch or parameter handling. We believe a. is better for the extensions ecosystem. However, if other browsers prefer b. we will also accept that (since it supports the API proposal goal) |
### New Permissions | ||
| Permission Added | Proposed Warning | | ||
| ---------------- | -------------------------------------------------------- | | ||
| N/A | Permission’s API is used to “request declared optional permissions at run time rather than install time, so users understand why the permissions are needed and grant only those that are necessary” (according to documentation). The goal of this new method is for the extension to request site access, which is effectively a permission. We can adjust the description to not be restricted just to optional permissions. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"permission's API" -> "permissions API"? (There is no extension API called "permission")
Do we want this API to be unconditionally available to all extensions? I think that it would be good to put this behind a permission or manifest key that doesn't require a warning, because that makes it easier to statically determine whether extensions use this feature.
Otherwise it is rather unfeasible to enforce the policy of responsible use, and the API becomes useless as a signal to request attention from the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"permission's API" -> "permissions API"? (There is no extension API called "permission")
Correct, it was a typo.
Do we want this API to be unconditionally available to all extensions? ...
I'm not sure if I follow this.
- Permissions API does not require a warning. Calling
permissions.request(x)
could trigger a warning iff x has a warning. - Permissions API doesn't require an entry in manifest permissions
Enforcing responsible use does not have to be connected to whether the permission 'Permissions API' is present, instead each browser can determine it (e.g limit to a number of calls if user has dismissed it on a site). Why would it be useless?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want this API to be unconditionally available to all extensions? ...
I'm not sure if I follow this.
I was wondering whether we should add a new permission or manifest key, because requiring either means that the set of extensions that can abuse it drops from all to only a few (that use it), which can enable reviewers in the extension store to pay closer attention to verify whether the use of the API is acceptable.
- Permissions API does not require a warning. Calling
permissions.request(x)
could trigger a warning iff x has a warning.
By "that doesn't require a warning" I was emphasizing that the new permission/manifest key does not need a permission message. There are several APIs that are behind permissions that do not trigger a warning message in the prompt. This could be another one.
Enforcing responsible use does not have to be connected to whether the permission 'Permissions API' is present, instead each browser can determine it (e.g limit to a number of calls if user has dismissed it on a site). Why would it be useless?
So from the browser perspective it doesn't matter, since the enforcement is based on the use of the API. In the broader ecosystem, it may be desirable to know whether an API may be used without running all extensions (e.g. for review, auditing, capability analysis, etc.). The manifest.json file is a machine-readable format, and a new permission (or manifest key) enables automatic scanning.
|
||
#### Other Alternatives considered | ||
|
||
- Action API is used to control the extension’s button in the browser’s toolbar. It’s exposed if the extension includes the "action" key in the manifest. This is troublesome since an extension could not have an action, but still want to show site access requests. We should not limit requests for extensions with actions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are use cases benefiting from the proposed API without action button? The current bullet point makes it sound like there are extensions without button that need the API. But the typical use case, i.e. shopping extension, would usually have a button.
An API to draw attention to the action button would be more generic and enable more use cases beyond just granting access to the top-level origin. It would also enable an extension to offer more context to the permission request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Chrome, an extension without an action can request host permissions, which can be withheld. To grant access, the user can click on the extension icon or extension entry in extensions menu. Once the extension has access, the extension is not clickable because it doesn't have an action.
Now, it's unlikely that an extension doesn't specify an action. The majority wants at least to specify the action's "default icon". However, that is not required and there are extensions that don't specify an action and require host permissions. For example, there is an extension that doesn't have an action and injects a script that makes google docs comments wider.
Originally, I was very undecided between permissions vs action. Went with permission for the reason explained, although I can also see argument why it would be better to have it with action
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved with the new comments addressed.
FYI: You can easily commit the requested changes through Githubs interface.
Co-authored-by: Rob Wu <[email protected]>
SHA: 0bd3171 Reason: push, by xeenon Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
SHA: 0bd3171 Reason: push, by xeenon Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Proposal for a new API method to allow the extension to show site access requests at runtime without any user gesture in a less-obtrusive way than with
permissions.request()