-
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
Changes from 5 commits
0337140
ce54af5
3a11106
c1d2c83
f3ec64f
97adc54
db2642b
42e10b0
e8431e9
5267c8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# permissions.showSiteAccessRequest() API | ||
|
||
## API Overview | ||
|
||
### Background | ||
|
||
Extensions can request host permissions via: | ||
- Manifest declared `host_permissions`, granted at install time by default | ||
- Manifest declared `optional_host_permissions`, granted at runtime after a user gesture by `<browser>.permissions.request()` | ||
- Manifest declared `matches` for a `content_script`, granted at install time by default | ||
|
||
In some browsers, users can withhold host permissions causing the extension to only have site access when the extension is invoked. For example, in Chrome a user can set an extension to run only "on click". When the extension is clicked, it gains site access to the tab's main frame origin (effectively acting like [`activeTab` permission](https://developer.chrome.com/docs/extensions/develop/concepts/activeTab#what-activeTab-allows). | ||
|
||
Each browser may decide how it signals the user when an extension is requesting access (e.g through the extensions menu). However, there is no way for an extension to explicitly signal at runtime it’s requesting site access after it was withheld without a user gesture and a heavy-weight permission dialog. | ||
|
||
|
||
### Objective | ||
|
||
Allow the extension to show site access requests at runtime without any user gesture in a less-obtrusive way than with `permissions.request()`. This can be done with a new API that: | ||
|
||
- Applies to a specific tab or document id | ||
- Doesn’t need to be made inside the handler for a user action | ||
- Shows the request in the UI, handled differently by each browser. See more in [UI Elements and User-Visible Effects](#ui-elements-and-user-visible\-effects) section | ||
- When accepted, grants always access to the site’s top origin | ||
- Resets the request on cross-origin navigation | ||
|
||
#### 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 without user action. For example, “shopping” extension wants to show site access when user navigates to “amazon.com” and access was withheld. | ||
|
||
### Consumers | ||
|
||
Extensions that want to signal the user when they need site access. | ||
|
||
## Implementation | ||
|
||
### API Schema | ||
|
||
``` | ||
// Shows a site access request. Request will only be signaled to the user if | ||
EmiliaPaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// extension can be granted access to site in the request (i.e., one specified | ||
// in host_permissions, optional_host_permissions, a content script match | ||
// pattern, or an applicable activeTab site). | ||
// Resolves whether the request is valid and is signaled to the user. | ||
EmiliaPaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Promise<bool> <browser>.permissions.showSiteAccessRequest( | ||
EmiliaPaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// The id of the tab where site access requests can be shown. If provided, | ||
// the request is shown on the specified tab and is removed when the tab | ||
// navigates to a new origin. | ||
// Chrome requires either this or `documentId` to be specified. | ||
number?: tabId, | ||
// The id of a document where site access requests can be shown. Must be | ||
// the top-level document within a tab. If provided, the request is shown on | ||
// the tab of the specified document and is removed when the document | ||
// navigates to a new origin. | ||
// Chrome requires either this or `tabId` to be specified. | ||
string?: documentId, | ||
// The URL pattern where site access requests can be shown. If provided, | ||
// site access requests will only be shown on URLs that match this pattern. | ||
// Browsers may require different levels of specificity. | ||
string?: url | ||
EmiliaPaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
callback?: function, | ||
); | ||
|
||
// Removes a site access request, if existent. | ||
// Resolves whther the request was removed. | ||
Promise<bool> <browser>.permissions.removeSiteAccessRequest( | ||
EmiliaPaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// The id of the tab where site access request will be removed. | ||
// Chrome requires either this or `documentId` to be specified. | ||
number?: tabId, | ||
// The id of a document where site access request will be removed. | ||
// Chrome requires either this or `tabId` to be specified. | ||
string?: documentId, | ||
// The URL pattern where site access request will be removed. | ||
string?: url | ||
EmiliaPaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
callback?: function, | ||
); | ||
``` | ||
|
||
Note: We don’t support iframes since they are not included in the runtime host permissions UI. | ||
|
||
### 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more.
Correct, it was a typo.
I'm not sure if I follow this.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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.
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.
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 commentThe 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 commentThe 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 |
||
- `permissions.showSiteAccessRequest()` resolves when request is accepted/rejected. An extension could be requesting site access and be granted site access through another mechanism (e.g changing site access in the extensions menu). We would either return a) true if we consider permissions granted through other mechanisms or b) false, because permission wasn't explicitely granted through the request. a) adds complexity and b) may cause confusion. Thus, we consider better to resolve whether the request is valid, and separately extension can listen whether permission is granted through `permissions.onAdded()`. | ||
|
||
### Manifest Changes | ||
|
||
None. | ||
|
||
### Custom Bindings | ||
|
||
None. | ||
|
||
### Design and Implementation | ||
|
||
#### Persistence | ||
|
||
Showing a site access request is never persisted. | ||
|
||
#### Alignment with Other Vendors and Action APIs | ||
|
||
Each browser can decide how they want to signal the extension site access requests. Browsers may decide to ignore the request (e.g due to noisiness, or if an extension has no visible UI). | ||
On Chrome’s side, we are exploring adding an ‘Allow’ chip in the extensions toolbar. | ||
|
||
## User Experience | ||
|
||
### UI Elements and User Visible-Effects | ||
|
||
Each browser will handle the request as desired. On Chrome’s side, we are considering showing an ‘Allow’ button in the toolbar for these requests. On click, it would grant persistent access to the site’s origin (which can be again withheld by the user) | ||
|
||
!["Site access request on Chrome toolbar"](./assets/permissions-requestSiteAccess-chrome-toolbar.png) | ||
|
||
We would also provide a way for users to silence the requests for an extension through a setting in the extensions menu and in chrome://extensions. | ||
|
||
!["Extensions menu on Chrome"](./assets/permissions-requestSiteAccess-chrome-menu.png) | ||
|
||
#### Attribution | ||
The site access request will be attributed directly to the extension. | ||
|
||
## Security and Privacy | ||
|
||
### Exposed Sensitive Data | ||
|
||
This API does not directly expose any sensitive data to the extension. However, it could lead to the extension gaining access to the site. | ||
|
||
### Abuse Scenarios | ||
|
||
Extensions can enable site access requests on every tab, which could be annoying to the user. | ||
|
||
#### Mitigations | ||
Attacks of annoyance are not in our threat model. Extensions can have annoying behaviors, but they risk uninstallation. | ||
On the browser side, we can place some restrictions to limit noisiness: | ||
Rob--W marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- User can decide whether they want to see site access requests for an specific extension | ||
- We can explore setting a max amount of times the request is shown when the user ignores it. | ||
xeenon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Additional Security Considerations | ||
None | ||
|
||
## Alternatives | ||
|
||
### Existing Workarounds | ||
|
||
Users can change an extension's site access. The only way for extensions to signal the user they want to regain access to the site is through permissions.request() flow which is noisy and requires a user gesture. Otherwise, they rely on the user realizing through the browser UI (e.g extensions menu). | ||
|
||
Extensions have no way to signal the user that they want access to the site, and rely on the user realizing through the browser UI (e.g extensions menu) | ||
|
||
### Other Alternatives Considered | ||
|
||
Specifying URL patterns instead of tabId or documentId in `permissions.requestSiteAccess` or in the extension's manifest. 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. This should not be a passive, "hey, I think I can do something here", it should be a "hey, you, the user, probably want me to do something here". | ||
- 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 (even by not allowing broad match patterns). | ||
- It's too close to host permissions themselves. We suspect that the vast majority of extensions would just have the same field match as in their host permissions, since there is no more knowledge at manifest time about why the extension would run on a specific site. | ||
|
||
### Open Web API | ||
This is related to the extensions showing site access requests in the browser; it doesn't affect the web. |
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:
activeTab
)Between these there are a couple more cases:
"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: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.
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:To fit into this proposal:
host_permissions
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:
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!
permissions.request()
allows an extension to request site access after a user actionLet's have an example now (similar to Oliver's on previous comment). In Chrome:
<all_urls>
in host_permissionssite.com
site access to "on click"site.com/useful
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.
@fregante
Extension cannot ask further host permissions. It would ask for host_permissions that were withheld by the user
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
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 gettab.url
and/ortab.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. callpermissions.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
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, ...windows.getCurrent()
to get more informationCurrently, 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
User withholding host permissions is not a common practice today. However, we expect that to change in the future because:
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.
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
ordocumentId
to be provided andurl
can be added on top of that.