Host permissions

A Collection of Interesting Ideas,

This version:
https://patrickkettner.github.io/quostibel/host-permissions.html
Issue Tracking:
GitHub
Inline In Spec
Editor:
Patrick Kettner

Abstract

This specification defines host permissions, the access they grant to URLs, their effect on cross-origin fetch, and the activeTab permission.

1. Host permissions

A host permission is a match pattern listed in host_permissions, or granted at runtime per § 1.2 Granting host permissions. Together the extension’s granted host permissions form its granted host permissions.

An extension has access to a URL url if all of the following are true:

  1. url is not restricted per § 1.1 Restricted URLs.

  2. url is matched by a match pattern in the extension’s granted host permissions, or by a temporary host permission granted through § 1.4 User gestures and activeTab.

Access to a URL is the single gate used throughout this specification and by the browser APIs for at least:

1.1. Restricted URLs

A host permission grants access to a URL only when the URL’s scheme is one of the schemes permitted in a match pattern; <all_urls> is no exception. This governs every access path that is mediated by host permissions (content scripts, and API access such as webRequest, cookies, and tabs). It does not by itself describe a browser-specific debugging API such as Chrome’s debugger permission, which is out of scope for this section; where such an API exists, an implementation should state its own access boundary rather than relying on this one, since the two need not coincide. In Chrome specifically, that debugging API bypasses the requirement that a URL fall within the extension’s granted host permissions, while remaining subject to the scheme and specific-host restrictions in this section. External remote debugging of a browser instance is outside this specification’s scope regardless.

Implementations additionally restrict specific hosts and schemes beyond what match pattern parsing alone would allow, independently of whether a granted match pattern would otherwise match:

Should this specification normatively list restricted hosts and schemes, require the restricted set to be discoverable at runtime, or leave it implementation-defined as today?

No implementation currently exposes the restricted set to an extension at runtime.

1.2. Granting host permissions

A match pattern listed in host_permissions is a required host permission.

An optional host permission is a host permission the extension may hold without it being granted at install: a pattern listed in optional_host_permissions, or one listed in host_permissions that the user agent has withheld until requested. An optional host permission is not part of the extension’s granted host permissions until granted.

Chrome and Firefox both grant required host permissions automatically at install time, then let the user subsequently withhold a granted host permission from a specific site through browser UI, at which point the extension’s effective access to that site reverts to a runtime-request flow even though the permission is still listed as required in the manifest. WebKit’s engine performs no automatic grant at all, for either required or optional host permissions; the embedding application is responsible for presenting required permissions to the user (for example at install or update) and recording the result, and nothing in the engine forces this to happen or guarantees a required host permission is granted by the time the extension runs.

This specification does not require required host permissions to be granted automatically at install, nor does it require user consent before every use. The standardized optional_host_permissions manifest key lets an extension author declare which host permissions are not required for core functionality and must be requested at runtime via request(); whether permissions listed in host_permissions are granted automatically at install, deferred to a runtime consent step, or made revocable or withholdable by the user is left to the implementation (w3c/webextensions#119, closed 2022-10-18).

To request a set of host permissions, an extension calls request() with those match patterns in origins. This may only be called from a privileged extension context and only while handling a user activation. The implementation must either add each requested pattern to the extension’s granted host permissions, or deny the entire request; a partial grant of a single request() call is not observable by the extension.

{
  "optional_host_permissions": ["https://*.example.com/*"]
}
let granted = await browser.permissions.request({
  origins: ["https://*.example.com/*"]
});

1.3. Cross-origin fetch

A request made from a privileged extension context whose target URL is matched by the extension’s granted host permissions is exempt from Fetch § 3.3 CORS protocol: the request proceeds, and the response is made available to the requesting script, without regard to Access-Control-Allow-Origin or any other CORS response header.

A request made from a content script context is not exempt from CORS on the basis of the extension’s host permissions. Such a request is subject to exactly the cross-origin rules that would apply to a request made by the page the content script is running within: same-origin requests succeed as normal, and cross-origin requests succeed only if the target server’s response grants access under Fetch § 3.3 CORS protocol. A granted host permission does not change this outcome, even <all_urls>.

Chrome, Firefox, and Safari arrived at this content-script rule differently:

Safari’s content-script fetch behavior has therefore never differed by manifest version: content scripts have always been subject to the same cross-origin rules as the page, matching Chrome’s and Firefox’s current (post-MV3-convergence) behavior rather than Firefox’s legacy MV2 exemption.

An extension with "host_permissions": ["https://api.example.com/*"] can call fetch("https://api.example.com/data") from its background service worker regardless of api.example.com’s CORS headers. The same call made from a content script injected into https://news.example/ succeeds only if https://api.example.com/data’s response includes an Access-Control-Allow-Origin header permitting https://news.example.

1.4. User gestures and activeTab

A user activation is transient activation of the document handling the interaction, extended to browser-chrome surfaces that have no document at all: clicking the extension’s toolbar action, invoking one of its keyboard commands, choosing one of its context menu items, or (implementation-defined) selecting it from the address bar. A user activation triggered from one of those surfaces is scoped to the extension it was directed at, the same way transient activation is scoped to a browsing context.

If an extension declares the activeTab permission, then each time a user activation for that extension occurs while a tab is active, the extension is granted a temporary host permission for that tab: for the remainder of the tab’s current navigation, the extension has access to a URL matching the tab’s current URL as if that URL were covered by a granted host permission, and the extension is granted the tabs permission for that tab (exposing its url, title, and favIconUrl).

A temporary host permission does not persist across navigation of the tab’s top-level document to a different origin; a fresh user activation is required after such a navigation. It does not grant access to any other tab, and it does not add anything to the extension’s granted host permissions as observed by getAll().

When is the temporary grant activeTab creates revoked? Chrome, Firefox, and Safari disagree:

Tracked at w3c/webextensions#657.

{
  "permissions": ["activeTab"]
}
A user clicks the extension’s toolbar icon while viewing https://example.com/. The extension is granted access to https://example.com/ for that tab until the tab navigates to a different origin; it still has no access to any other tab, and no access to https://example.com/ in a new tab the user opens afterward.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/

Issues Index

Should this specification normatively list restricted hosts and schemes, require the restricted set to be discoverable at runtime, or leave it implementation-defined as today? ↵
When is the temporary grant activeTab creates revoked? Chrome, Firefox, and Safari disagree:

Tracked at w3c/webextensions#657.

↵