Copyright © 2024 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
This specification defines common infrastructure that other specifications can use to interact with browser permissions. These permissions represent a user's choice to allow or deny access to "powerful features" of the platform. For developers, the specification standardizes an API to query the permission state of a powerful feature, and be notified if a permission to use a powerful feature changes state.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
This is a work in progress.
This document was published by the Web Application Security Working Group as a Working Draft using the Recommendation track.
Publication as a Working Draft does not imply endorsement by W3C and its Members.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 03 November 2023 W3C Process Document.
This section is non-normative.
Specifications can define features that are explicitly identified as a powerful feature. These features are said to be "powerful" in that they can have significant privacy, security, and performance implications. As such, users rely on user agents to deny sites the ability to use these features until they have given express permission, and usually only granting this ability for a limited amount of time. Express permission to allow a site to use a powerful feature is generally given and controlled through browser UI, as illustrated below.
In this sense, a permission represents the current state of user consent for certain types of features, and particularly "powerful features". Ultimately the user retains control of these permissions and have the ability to manually grant or deny permissions through user preferences. Further, user agents assist users in managing permissions by, for example, hiding and automatically denying certain permission prompts that would otherwise be a nuisance, and automatically expiring granted permissions if a user doesn't visit a website for some time.
This section is non-normative.
This example uses the Permissions API to decide whether local news should be shown using the Geolocation API or with a button offering to add the feature.
const { state } = await navigator.permissions.query({
name: "geolocation"
});
switch (state) {
case "granted":
showLocalNewsWithGeolocation();
break;
case "prompt":
showButtonToEnableLocalNews();
break;
case "denied":
showNationalNews();
break;
}
This example simultaneously checks the state of the "geolocation"
and "notifications"
powerful features:
const queryPromises = ["geolocation", "notifications"].map(
name => navigator.permissions.query({ name })
);
for await (const status of queryPromises) {
console.log(`${status.name}: ${status.state}`);
}
This example is checking the permission state of the available cameras.
const devices = await navigator.mediaDevices.enumerateDevices();
// filter on video inputs, and map to query object
const queries = devices
.filter(({ kind }) => kind === "videoinput")
.map(({ deviceId }) => ({ name: "camera", deviceId }));
const promises = queries.map((queryObj) =>
navigator.permissions.query(queryObj)
);
try {
const results = await Promise.all(promises);
// log the state of each camera
results.forEach(({ state }, i) => console.log("Camera", i, state));
} catch (error) {
console.error(error);
}
This section specifies a model for permissions to use powerful features on the Web platform.
A permission represents a user's decision to allow a web application to use a powerful feature. This decision is represented as a permission state.
Express permission refers to the user granting the web application the ability to use a powerful feature.
Conceptually, a permission for a powerful feature can be in one of the following states:
To ascertain new information about the user's intent, a user agent MAY collect and interpret information about a user's intentions. This information can come from explicit user action, aggregate behavior of both the relevant user and other users, or implicit signals this specification hasn't anticipated.
Every permission has a lifetime, which is the duration for which a particular permission remains "granted" before it reverts back to its default state. A lifetime could be until a particular Realm is destroyed, until a particular top-level browsing context is destroyed, a particular amount of time, or be infinite. The lifetime is negotiated between the end-user and the user agent when the user gives express permission to use a feature—usually via some permission UI or user-agent defined policy.
Every permission has a default state (usually "prompt"), which is the state that the permission is in when the user has not yet given express permission to use the feature or it has been reset because its lifetime has expired.
The user agent maintains a single permission store which is a list of permission store entries. Each particular entry denoted by its descriptor and key can only appear at most once in this list.
The user agent MAY remove entries from the permission store when their respective permission's lifetime has expired.
A permission store entry is a tuple
of PermissionDescriptor
descriptor, permission key key, and state state.
To get a permission store entry given a
PermissionDescriptor
descriptor and permission key
key:
To set a permission store entry given a
PermissionDescriptor
descriptor, a permission key key,
and a state state, run these steps:
To remove a permission store entry given a
PermissionDescriptor
descriptor and permission key
key, run these steps:
A permission key has its type defined by a feature's permission key type.
To determine whether a permission key key1 is equal to a permission key key2, given a
PermissionDescriptor
descriptor, run the following steps:
name
,
passing key1 and key2.
A powerful feature is a web platform feature (usually an API) for which a user gives express permission before the feature can be used. Except for a few notable exceptions (e.g., the Notifications API Standard), most powerful features are also policy-controlled features. For powerful features that are also policy-controlled features, [Permissions-Policy] controls whether a document is allowed to use a given feature. That is, a powerful feature can only request express permission from a user if the document has permission delegated to it via the corresponding policy-controlled feature (see example below). Subsequent access to the feature is determined by the user having "granted" permission, or by satisfying some criteria that is equivalent to a permission grant.
A powerful feature is identified by its name, which is a string literal (e.g., "geolocation").
The user agent tracks which powerful features the user has permission to use via the environment settings object.
Each powerful feature can define zero or more additional aspects. An aspect is defined as WebIDL dictionary that
inherits from PermissionDescriptor
and serves as a WebIDL
interface's permission descriptor type.
The permissions task source is a task source used to perform permissions-related tasks in this specification.
When a conforming specification specifies a powerful feature it:
PermissionDescriptor
.
Registering the newly specified powerful features in the Permissions Registry gives this Working Group an opportunity to provide feedback and check that integration with this specification is done effectively.
PermissionDescriptor
or one of its subtypes. If unspecified, this defaults to
PermissionDescriptor
.
The feature can define a partial order on descriptor
instances. If descriptorA is stronger than descriptorB, then if descriptorA's
permission state is "granted
", descriptorB's permission state must also be "granted
", and if descriptorB's permission state is "denied
", descriptorA's permission state must also
be "denied
".
Some powerful features have more information associated with them than just a
PermissionState
. Each of these features defines an extra permission data type.
For example, getUserMedia
()
needs to determine which cameras
the user has granted permission to access.
If a DOMString
name names one of these features, then name's
extra permission data for
an optional environment settings object settings is the result of the
following algorithm:
If specified, the extra permission data algorithm is usable for this feature.
PermissionStatus
or one of its subtypes. If unspecified, this defaults to
PermissionStatus
.
Takes an instance of the permission descriptor type and a new or
existing instance of the permission result type, and updates the
permission result type instance with the query result. Used by
Permissions
' query
(permissionDesc)
method and the
PermissionStatus
update steps. If unspecified, this defaults to the default permission query algorithm.
The default permission query algorithm, given a
PermissionDescriptor
permissionDesc and a PermissionStatus
status, runs the following steps:
status
's state
to permissionDesc's
permission state.
The type of permission key used by the feature. Defaults to origin. A feature that specifies a custom permission key type MUST also specify a permission key generation algorithm.
Takes an environment settings object, and returns a new permission key. If unspecified, this defaults to the default permission key generation algorithm. A feature that specifies a custom permission key generation algorithm MUST also specify a permission key comparison algorithm.
The default permission key generation algorithm, given an environment settings object settings, runs the following steps:
Takes two permission keys and returns a boolean that shows whether the two keys are equal. If unspecified, this defaults to the default permission key comparison algorithm.
The default permission key comparison algorithm, given permission keys key1 and key2, runs the following steps:
Takes no arguments. Updates any other parts of the implementation that need to be kept in sync with changes in the results of permission states or extra permission data.
If unspecified, this defaults to running react to the user revoking permission.
Specifications that define one or more powerful features SHOULD suggest a permission lifetime that is best suited for the particular feature. Some guidance on determining the lifetime of a permission is noted below, with a strong emphasis on user privacy. If no lifetime is specified, the user agent provides one.
When the permission lifetime expires for an origin:
An PermissionState
value that serves as a permission's default state of a powerful feature.
If not specified, the permission's default state is
"prompt
".
A default powerful feature is a powerful feature with all of the above types and algorithms defaulted.
To get the current
permission state, given a name name and an optional
environment settings object settings, run the following steps. This algorithm
returns a PermissionState
enum value.
PermissionDescriptor
with name
initialized to name.
A descriptor's permission state, given an optional
environment settings object settings is the result of the following algorithm.
It returns a PermissionState
enum value:
denied
".
name
.
Document
run the
following step:
Document
.
denied
".
PermissionState
enum value from entry's
state.
PermissionState
enum value that represents the permission state of
feature, taking into account any permission state constraints
for descriptor's name
.
As a shorthand, a DOMString
name's permission state is the permission state
of a PermissionDescriptor
with its name
member set to
name.
To request permission to use a descriptor, the user
agent must perform the following steps. This algorithm returns either
"granted
" or "denied
".
prompt
", return
current state and abort these steps.
granted
"; otherwise to "denied
". The
user's interaction may provide new information about the user's intent for the
origin.
This is intentionally vague about the details of the permission UI and how the user agent infers user intent. User agents should be able to explore lots of UI within this framework.
As a shorthand, requesting permission to use a DOMString
name, is the same as
requesting permission to use a PermissionDescriptor
with its
name
member set to name.
To prompt the user to choose one or more options associated with a given
descriptor and an optional boolean
allowMultiple (default false), the user agent must perform the following
steps. This algorithm returns either "denied
" or the user's
selection.
denied
", return
"denied
" and abort these steps.
granted
", the
user agent may return one (or more if allowMultiple is true) of options chosen by
the user and abort these steps. If the user agent returns without prompting, then
subsequent prompts for the user to choose
from the same set of options with the same descriptor must return the same option(s),
unless the user agent receives new information about the user's intent.
denied
".
This is intentionally vague about the details of the permission UI and how the user agent infers user intent. User agents should be able to explore lots of UI within this framework (e.g., a permission prompt could time out and automatically return "denied" without the user making an explicit selection).
As a shorthand, prompting the user to choose from options associated with a
DOMString
name, is the same as prompting the user to choose from those options
associated with a PermissionDescriptor
with its name
member
set to name.
When the user agent learns that the user no longer intends to grant permission to use a
feature described by the PermissionDescriptor
descriptor in the context described
by the permission key key, react to the user revoking permission by
running these steps:
name
's permission revocation algorithm.
WebIDL[Exposed=(Window,Worker)]
interface Permissions
{
Promise<PermissionStatus
> query
(object permissionDesc);
};
dictionary PermissionDescriptor
{
required DOMString name
;
};
When the query()
method is invoked, the user agent MUST run the
following query a permission algorithm, passing the
parameter permissionDesc:
Window
object, then:
Document
is not
fully active, return a promise rejected with an
"InvalidStateError
" DOMException
.
PermissionDescriptor
.
name
"] is not supported, return a promise rejected with a TypeError
.
name
's permission descriptor type.
PermissionStatus
with typedDescriptor.
[[query]]
internal slot.
name
's permission query algorithm, passing query and status.
WebIDL[Exposed=(Window,Worker)]
interface PermissionStatus
: EventTarget {
readonly attribute PermissionState
state
;
readonly attribute DOMString name
;
attribute EventHandler onchange
;
};
enum PermissionState
{
"granted
",
"denied
",
"prompt
",
};
PermissionStatus
instances are created with a [[query]] internal slot,
which is an instance of a feature's permission descriptor type.
The "granted
", "denied
", and "prompt
" enum values
represent the concepts of "granted", "denied", and
"prompt" respectively.
To create a PermissionStatus
for a given
PermissionDescriptor
permissionDesc:
name
.
The name
attribute returns the value it was initialized to.
The state
attribute returns the latest value that was set on the current
instance.
The onchange
attribute is an event handler whose corresponding event handler event type is change
.
Whenever the user agent is aware that the state of a PermissionStatus
instance status has changed, it asynchronously runs the PermissionStatus
update steps:
Window
object, then:
[[query]]
internal slot.
name
's permission query algorithm, passing query and status.
change
at status.
A PermissionStatus
object MUST NOT be garbage collected if it has an event listener whose type is change
.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, MUST NOT, OPTIONAL, and SHOULD in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
Two classes of product can claim conformance to this specification: user agents and other specifications (i.e., a technical report that specifies a powerful feature in a manner that conforms to the requirements of this specification).
This section is non-normative.
Although both this specification and the Permissions Policy specification deal with "permissions", each specification serves a distinct purpose in the platform. Nevertheless, the two specifications do explicitly overlap.
On the one hand, this specification exclusively concerns itself with powerful features whose access is managed through a user-agent mediated permissions UI (i.e., permissions where the user gives express consent before that feature can be used, and where the user retains the ability to deny that permission at any time for any reason). These powerful features are registered in the Permissions Registry.
On the other hand, the Permissions Policy specification allows developers to
selectively enable and disable policy-controlled features through a "permissions policy" (be it a HTTP header or the allow
attribute). In that sense, the
Permissions Policy subsumes this specification in that Permissions Policy governs
whether a feature is available at all, independently of this specification. These
policy-controlled features are also registered in the Permissions Registry.
A powerful feature that has been disabled by the Permissions Policy specification always has its permission state reflected as "denied" by this specification. This occurs because reading the current permission relies on [HTML]'s "allowed to use" check, which itself calls into the Permissions Policy specification. Important to note here is the sharing of permission names across both specifications. Both this specification and the Permissions Policy specification rely on other specifications defining the names of the permission and name, and they are usually named the same thing (e.g., "geolocation" of the Geolocation API, and so on).
Finally, it's not possible for a powerful feature to ever become "granted" through any means provided by the Permissions Policy specification. The only way that a powerful feature can be "granted" is by the user giving express permission or by some user agent policy.
For the purposes of user-agent automation and application testing, this document defines extensions to the [WebDriver] and [WebDriver-BiDi] specifications. It is OPTIONAL for a user agent to support them.
WebIDLdictionary PermissionSetParameters
{
required object descriptor
;
required PermissionState
state
;
};
To set a permission given a PermissionDescriptor
descriptor, a PermissionState
state, an
optional origin, and an optional user agent:
This document defines the following extension commands for the [WebDriver] specification.
HTTP Method | URI Template |
---|---|
POST | /session/{session id}/permissions |
The Set Permission
extension command simulates user modification of a PermissionDescriptor
's
permission state.
The remote end steps are:
PermissionSetParameters
. If this throws an exception, return an invalid argument error.
state
is an inappropriate
permission state for any implementation-defined reason, return an invalid argument error.
For example, user agents that define the "midi" powerful feature as
"always on" can choose to reject a command to set the permission state to
"denied
" at this step.
descriptor
.
name
"). If this throws an
exception, return a invalid argument error.
state
.
null
.
This document defines the following extension modules for the [WebDriver-BiDi] specification.
The permissions module contains commands for managing the remote end browser permissions.
PermissionsCommand = (
permissions.setPermission
)
permissions.PermissionDescriptor = {
name: text,
}
The permissions.PermissionDescriptor
type represents a PermissionDescriptor
.
permissions.PermissionState = "granted" / "denied" / "prompt"
The permissions.PermissionState
type represents a PermissionState
.
The Set Permission command simulates user
modification of a PermissionDescriptor
's permission state.
permissions.setPermission = (
method: "permissions.setPermission",
params: permissions.SetPermissionParameters
)
permissions.SetPermissionParameters = {
descriptor: permissions.PermissionDescriptor,
state: permissions.PermissionState,
origin: text,
? userContext: text,
}
EmptyResult
The remote end steps with session and command parameters are:
descriptor
field of command
parameters.
name
field of descriptor
representing name
.
state
field of command parameters.
userContext
field of command
parameters, if present, and default
otherwise.
PermissionSetParameters
permission
name's permission descriptor type. If this conversion
throws an exception, return error with error code invalid argument.
origin
field of command parameters.
null
.
This section is non-normative.
This W3C Registry provides a centralized place to find the policy-controlled features and/or powerful features of the web platform. Through the change process it also helps assure permissions in the platform are consistently specified across various specifications.
By splitting the registry into standardized permissions and provisional permissions, the registry also provides a way to track the status of these features.
The change process for adding and/or updating this registry is as follows:
"super-awesome"
). Make sure the string is linkable by wrapping it a dfn
element.
'self'
).
For a permission to appear in the table of standardized permissions, and thus be considered a standardized permission, it needs to meet the following criteria:
Each permission is identified by a unique literal string. In the case of Permissions Policy, the string identifies a policy-controlled features. Similarly, in the Permissions specification the string identifies a powerful feature.
Identifying string | Is policy-controlled feature? | Is powerful feature? | Specification | Implementations | ||
---|---|---|---|---|---|---|
Chromium | Gecko | WebKit | ||||
"geolocation" | YES | YES | Geolocation API | YES | YES | YES |
"notifications" | NO | YES | Notifications API Standard | YES | YES | YES |
"push" | NO | YES | Push API | YES | YES | YES |
"web-share" | YES | NO | Web Share API | YES | YES | YES |
Provisional permissions are permissions that are not yet standardized (i.e., they are either experimental, still in the incubation phase, or are only implemented in a single browser engine).
Identifying string | Is policy-controlled feature? | Is powerful feature? | Specification | Implementations | ||
---|---|---|---|---|---|---|
Chromium | Gecko | WebKit | ||||
"accelerometer" | YES | YES | DeviceOrientation Event Specification | YES | NO | NO |
"window-management" | YES | YES | Window Management | YES | NO | NO |
"local-fonts" | YES | YES | Local Font Access | YES | NO | NO |
An adversary could use a permission state as an element in creating a "fingerprint" corresponding to an end-user. Although an adversary can already determine the state of a permission by actually using the API, that often leads to a UI prompt being presented to the end-user (if the permission was not already "granted"). Even though this API doesn't expose new fingerprinting information to websites, it makes it easier for an adversary to have discreet access to this information.
A user agent SHOULD provide a means for the user to review, update, and reset the permission state of powerful features associated with an origin.
There are no documented security considerations at this time. Readers are instead encouraged to read section D. Privacy considerations.
WebIDL[Exposed=(Window)]
partial interface Navigator {
[SameObject] readonly attribute Permissions
permissions
;
};
[Exposed=(Worker)]
partial interface WorkerNavigator {
[SameObject] readonly attribute Permissions
permissions
;
};
[Exposed=(Window,Worker)]
interface Permissions
{
Promise<PermissionStatus
> query
(object permissionDesc);
};
dictionary PermissionDescriptor
{
required DOMString name
;
};
[Exposed=(Window,Worker)]
interface PermissionStatus
: EventTarget {
readonly attribute PermissionState
state
;
readonly attribute DOMString name
;
attribute EventHandler onchange
;
};
enum PermissionState
{
"granted
",
"denied
",
"prompt
",
};
dictionary PermissionSetParameters
{
required object descriptor
;
required PermissionState
state
;
};
This section is non-normative.
The editors would like to thank Adrienne Porter Felt, Anne van Kesteren, Domenic Denicola, Jake Archibald and Wendy Seltzer for their help with the API design and editorial work.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: