Permissions

Editor’s Draft,

This version:
https://w3c.github.io/permissions/
Latest published version:
https://www.w3.org/TR/permissions/
Feedback:
public-webappsec@w3.org with subject line “[permissions] … message topic …” (archives)
Issue Tracking:
GitHub
Inline In Spec
Editors:
Mounir Lamouri (Google Inc.)
Marcos Cáceres (Mozilla)
Jeffrey Yasskin (Google Inc.)
Participate:
We are on Github.
File a bug.
Commit history.
Implementation status:
Blink/Chromium
Gecko
Not Ready For Implementation

This spec is not yet ready for implementation. It exists in this repository to record the ideas and promote discussion.

Before attempting to implement this spec, please contact the editors.


Abstract

The Permissions Standard defines common infrastructure for other specifications that need to interact with browser permissions. It also defines an API to allow web applications to query and request changes to the status of a given permission.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

Changes to this document may be tracked at https://github.com/w3c/webappsec.

The (archived) public mailing list public-webappsec@w3.org (see instructions) is preferred for discussion of this specification. When sending e-mail, please put the text “permissions” in the subject, preferably like this: “[permissions] …summary of comment…

This document was produced by the Web Application Security Working Group.

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 15 September 2020 W3C Process Document.

1. Scope of this document

This section is non-normative.

This document specifies a model and an API to query and request permissions to powerful features on the Web platform. Web APIs have different ways to deal with permissions. The [notifications] API allows developers to request a permission and check the permission status explicitly. Others expose the status to web pages when they try to use the API, like the [geolocation-API] which fails if the permission was not granted without allowing the developer to check beforehand.

The Permissions API provides tools for developers to control when permission prompts are shown and to relinquish permissions that are no longer needed.

The solution described in this document is meant to be extensible, but isn’t meant to be applicable to all the current and future permissions available in the web platform. Working Groups that are creating specifications whose permission model doesn’t fit in the model described in this document should contact the editors by filing an issue.

2. Privacy considerations

This section is non-normative.

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 permission request UI being presented to the end-user (if the permission was not already "granted"). Thus, 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. Thus, implementations are encouraged to have an option for users to block (globally or selectively) the querying of permission states.

3. Definitions

New information about the user’s intent
The UA may collect information about a user’s intentions in any way its authors believe is appropriate. This information can come from explicit user action, aggregate behavior of both the relevant user and other users, or other sources this specification hasn’t anticipated.
Powerful feature
A feature of a UA that some code might not be allowed to access, for example because its environment settings object doesn’t satisfy some criteria, or because the user hasn’t given permission.

4. Descriptions of permission requests

dictionary PermissionDescriptor {
  required PermissionName name;
};

Each powerful feature has one or more aspects that websites can request permission to access. To describe these aspects, each feature defines a subtype of PermissionDescriptor to be its permission descriptor type.

The "midi" feature has two aspects: access to normal messages, and access to system exclusive messages. Thus, its permission descriptor type is:

dictionary MidiPermissionDescriptor : PermissionDescriptor {
  boolean sysex = false;
};

The "bluetooth" feature lets sites request to access whatever Bluetooth devices are close to to the user’s device. Thus, its permission descriptor type is:

dictionary BluetoothPermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
  sequence<BluetoothRequestDeviceFilter> filters;
  sequence<BluetoothServiceUUID> optionalServices = [];
};

General access to Bluetooth devices is represented by {name: 'bluetooth'}; access to a particular device is represented by {name: 'bluetooth', deviceId: "id"}; and access to a device with a particular service is represented by {name: 'bluetooth', filters: [{services: ['service']}]}

5. Permission states

The user agent is responsible for tracking what powerful features each realm has the user’s permission to use. Other specifications can use the operations defined in this section to retrieve the UA’s notion of what permissions are granted or denied, and to ask the user to grant or deny more permissions.

Other specifications can also add more constraints on the UA’s behavior in these algorithms.

Within this section, descriptor is an instance of the permission descriptor type of the powerful feature named by descriptor.name.

5.1. Reading the current permission state

A descriptor’s permission state is the result of the following algorithm, which returns one of "granted", "prompt", or "denied":

  1. If the current settings object is a non-secure context and descriptor.name isn’t allowed in non-secure contexts, then return "denied".
  2. If there was a previous invocation of this algorithm with the same descriptor and current settings object, returning previousResult, and the UA has not received new information about the user’s intent since that invocation, return previousResult.
  3. Return whichever of the following options most accurately reflects the user’s intent for the calling algorithm:
    succeed without prompting the user
    "granted"
    show the user a prompt to decide whether to succeed
    "prompt"
    fail without prompting the user
    "denied"

Safari is the only known UA that returns different results from this algorithm for different settings objects with the same origin. We should test which of the several possible settings objects it uses.

As a shorthand, a PermissionName name’s permission state is the permission state of a PermissionDescriptor with its name member set to name.

Some powerful features have more information associated with them than just a PermissionState. For example, getUserMedia() needs to determine which cameras the user has granted the current realm permission to access. Each of these features defines an extra permission data type. If a PermissionName name names one of these features, then name’s extra permission data is the result of the following algorithm:

  1. If there was a previous invocation of this algorithm with the same name and current settings object, returning previousResult, and the UA has not received new information about the user’s intent since that invocation, return previousResult.
  2. Return the instance of name’s extra permission data type that matches the UA’s impression of the user’s intent.

5.2. Requesting more permission

Spec authors, please note that algorithms in this section can wait for user input; so they shouldn’t be used from other algorithms running on the main thread.

To request permission to use a descriptor, the UA must perform the following steps. This algorithm returns either "granted" or "denied".

  1. Let current state be the descriptor’s permission state.
  2. If current state is not "prompt", return current state and abort these steps.
  3. If this algorithm is not triggered by user activation, the UA may return "denied" and abort these steps.
  4. Ask the user’s permission for the calling algorithm to use the powerful feature described by descriptor.
  5. If the user grants permission, return "granted"; otherwise return "denied". If the user’s interaction indicates they intend this choice to apply to other realms, then treat this as new information about the user’s intent for other realms with the same origin.

    This is intentionally vague about the details of the permission UI and how the UA infers user intent. UAs should be able to explore lots of UI within this framework.

As a shorthand, requesting permission to use a PermissionName 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 of several options associated with a descriptor, the UA must perform the following steps. This algorithm returns either "denied" or one of the options.

  1. If descriptor’s permission state is "denied", return "denied" and abort these steps.
  2. If descriptor’s permission state is "granted", the UA may return one of options and abort these steps. If the UA 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, unless the UA receives new information about the user’s intent.
  3. If this algorithm is not triggered by user activation, the UA may return "denied" and abort these steps.
  4. Ask the user to choose one of the options or deny permission, and wait for them to choose. If the calling algorithm specified extra information to include in the prompt, include it.
  5. If the user chose an option, return it; otherwise return "denied". If the user’s interaction indicates they intend this choice to apply to other realms, then treat this this as new information about the user’s intent for other realms with the same origin.

    This is intentionally vague about the details of the permission UI and how the UA infers user intent. UAs should be able to explore lots of UI within this framework.

As a shorthand, prompting the user to choose from options associated with a PermissionName name, is the same as prompting the user to choose from those options associated with a PermissionDescriptor with its name member set to name.

5.3. Reacting to users revoking permission

When the UA learns that the user no longer intends to grant permission for a realm to use a feature, it must queue a task on the Realm’s settings object’s responsible event loop to run that feature’s permission revocation algorithm.

6. Status of a permission

PermissionStatus

Firefox46+SafariNoneChrome43+
OperaYesEdge79+
Edge (Legacy)NoneIENone
Firefox for Android46+iOS SafariNoneChrome for Android43+Android WebViewNoneSamsung Internet4.0+Opera MobileYes
enum PermissionState {
  "granted",
  "denied",
  "prompt",
};

The "granted" state represents that the caller will be able to successfuly access the feature without having the user agent asking the user’s permission.

The "denied" state represents that the caller will not be able to access the feature.

The "prompt" state represents that the user agent will be asking the user’s permission if the caller tries to access the feature. The user might grant, deny or dismiss the request.

[Exposed=(Window,Worker)]
interface PermissionStatus : EventTarget {
  readonly attribute PermissionState state;
  attribute EventHandler onchange;
};

PermissionStatus instances are created with a [[query]] internal slot, which is an instance of a feature’s permission descriptor type.

To create a PermissionStatus for a given PermissionDescriptor permissionDesc, return a new instance of the permission result type for the feature named by permissionDesc.name, with the [[query]] internal slot initialized to permissionDesc.

PermissionStatus/state

Firefox46+SafariNoneChrome44+
OperaYesEdge79+
Edge (Legacy)NoneIENone
Firefox for Android46+iOS SafariNoneChrome for Android44+Android WebViewNoneSamsung Internet4.0+Opera MobileYes

The state attribute MUST return the latest value that was set on the current instance.

PermissionStatus/onchange

Firefox46+SafariNoneChrome43+
OperaYesEdge79+
Edge (Legacy)NoneIENone
Firefox for Android46+iOS SafariNoneChrome for Android43+Android WebViewNoneSamsung Internet4.0+Opera MobileYes

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 MUST asynchronously run the following steps:

  1. Run status@[[query]].name’s permission query algorithm, passing status@[[query]] and status.
  2. Queue a task on the permission task source to fire an event named change at status.
[Exposed=(Window)]
partial interface Navigator {
  readonly attribute Permissions permissions;
};
[Exposed=(Worker)]
partial interface WorkerNavigator {
  readonly attribute Permissions permissions;
};

8. Permissions interface

Permissions

Firefox46+SafariNoneChrome43+
OperaYesEdge79+
Edge (Legacy)NoneIENone
Firefox for Android46+iOS SafariNoneChrome for Android43+Android WebViewNoneSamsung Internet4.0+Opera MobileYes

Permissions/query

Firefox46+SafariNoneChrome43+
OperaYesEdge79+
Edge (Legacy)NoneIENone
Firefox for Android46+iOS SafariNoneChrome for Android43+Android WebViewNoneSamsung Internet4.0+Opera MobileYes
[Exposed=(Window,Worker)]
interface Permissions {
  Promise<PermissionStatus> query(PermissionDescriptor permissionDesc);

  Promise<PermissionStatus> request(PermissionDescriptor permissionDesc);

  Promise<PermissionStatus> revoke(PermissionDescriptor permissionDesc);
};

When the query() method is invoked, the user agent MUST run the following query a permission algorithm, passing the parameter permissionDesc:

  1. If permissionDesc.name has a permission descriptor type other than PermissionDescriptor, convert the underlying ECMAScript object to the permission descriptor type dictionary as described in [WEBIDL], then:
    • If that operation failed, return a Promise rejected with a TypeError and abort these steps.
    • Otherwise, set permissionDesc to the result of the operation.
  2. Let promise be a newly-created Promise.
  3. Return promise and continue the following steps asynchronously.
  4. Run the steps to create a PermissionStatus for permissionDesc, and let status be the result.
  5. Run status@[[query]].name’s permission query algorithm, passing status@[[query]] and status.
  6. Resolve promise with status.
If a developer wants to check multiple permissions at once, the editors recommend the use of Promise.all(). An example can be found in the Examples section.

When the request() method is invoked, the user agent MUST run the following algorithm, passing the parameter permissionDesc:

  1. If permissionDesc.name has a permission descriptor type other than PermissionDescriptor, convert the underlying ECMAScript object to the permission descriptor type dictionary as described in [WEBIDL], then:
    • If that operation failed, return a Promise rejected with a TypeError and abort these steps.
    • Otherwise, set permissionDesc to the result of the operation.
  2. Let promise be a newly-created Promise.
  3. Return promise and continue the following steps asynchronously.
  4. Run the steps to create a PermissionStatus for permissionDesc, and let status be the result.
  5. Run the permission request algorithm of the feature named permissionDesc.name with permissionDesc and status as arguments.
  6. If the previous step threw an exception, reject promise with that exception.
  7. Otherwise resolve promise with status.

When the revoke(permissionDesc) method is invoked, this constitutes new information about the user’s intent. The UA must return a new promise promise and run the following steps in parallel:

  1. If any tasks run due to § 5.3 Reacting to users revoking permission, wait for them to finish.
  2. Resolve promise with the result of query(permissionDesc).

9. Common permission algorithms

The boolean permission query algorithm, given a PermissionDescriptor permissionDesc and a PermissionStatus status, runs the following steps:

  1. Set status.state to permissionDesc’s permission state.

The boolean permission request algorithm, given a PermissionDescriptor permissionDesc and a PermissionStatus status, runs the following steps:

  1. Run the boolean permission query algorithm on permissionDesc and status.
  2. If status.state is not "prompt", abort these steps.
  3. Request permission to use permissionDesc.
  4. Run the boolean permission query algorithm again on permissionDesc and status.

    On browsers that don’t store permissions persistently within an environment settings object, this will always return "prompt", but still show the user an unnecessary prompt. That may mean that no permissions should use the boolean permission request algorithm, since it can never return an appropriate object-capability.

10. Permission Registry

enum PermissionName {
  "geolocation",
  "notifications",
  "push",
  "midi",
  "camera",
  "microphone",
  "speaker",
  "device-info",
  "background-sync",
  "bluetooth",
  "persistent-storage",
};

Each enumeration value in the PermissionName enum identifies a powerful feature. Each powerful feature has the following permission-related flags, algorithms, and types:

An allowed in non-secure contexts flag
By default, only secure contexts can use powerful features. If this flag is set for a feature, the UA may grant access to it in non-secure contexts too.
A permission descriptor type

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".

{name: "midi", sysex: true} ("midi-with-sysex") is stronger than {name: "midi", sysex: false} ("midi-without-sysex"), so if the user denies access to midi-without-sysex, the UA must also deny access to midi-with-sysex, and similarly if the user grants access to midi-with-sysex, the UA must also grant access to midi-without-sysex.

An optional extra permission data type
If specified, the extra permission data algorithm is usable for this feature. The feature will specify any constraints on the values this algorithm can return.
A permission result type
PermissionStatus or one of its subtypes. If unspecified, this defaults to PermissionStatus.
A permission query algorithm
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() method and the PermissionStatus update steps. If unspecified, this defaults to the boolean permission query algorithm.
A permission request algorithm
Takes an instance of the permission descriptor type and a newly-created instance of the permission result type. Uses the algorithms in § 5.2 Requesting more permission to show the user any necessary prompt to try to increase permissions, and updates the instance permission result type to match. May throw an exception if the request can fail exceptionally. (Merely being denied permission is not exceptional.) Used by Permissions' request() method. If unspecified, this defaults to the boolean permission request algorithm.
A permission revocation algorithm
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. Run by Permissions' revoke() method and run when the UA receives new information about the user’s intent. If unspecified, this defaults to doing nothing.

A boolean feature is a powerful feature with all of the above types and algorithms defaulted.

10.1. Geolocation

The "geolocation" permission is the permission associated with the usage of the [geolocation-API]. It is a boolean feature and is allowed in non-secure contexts.

10.2. Notifications

The "notifications" permission is the permission associated with the usage of the [notifications] API. It is a boolean feature and is allowed in non-secure contexts.

10.3. Push

The "push" permission is the permission associated with the usage of the [push-api].

permission descriptor type
dictionary PushPermissionDescriptor : PermissionDescriptor {
  boolean userVisibleOnly = false;
};

{name: "push", userVisibleOnly: false} is stronger than {name: "push", userVisibleOnly: true}.

10.4. Midi

The "midi" permission is the permission associated with the usage of [webmidi]. "midi" is allowed in non-secure contexts.

permission descriptor type
dictionary MidiPermissionDescriptor : PermissionDescriptor {
  boolean sysex = false;
};

{name: "midi", sysex: true} is stronger than {name: "midi", sysex: false}.

10.5. Media Devices

The "camera", "microphone" , and "speaker" permissions are associated with permission to use media devices as specified in [GETUSERMEDIA] and [audio-output]. "speaker" is allowed in non-secure contexts.

If the current settings object’s responsible browsing context or any of its ancestor browsing contexts has a browsing context container that isn’t an iframe element with the allowusermedia attribute specified, then the permission state of any descriptor with a name of "camera" or "microphone" must be "denied".

permission descriptor type
dictionary DevicePermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
};

A permission covers access to the device given in the associated descriptor.

If the descriptor does not have a deviceId, its semantic is that it queries for access to all devices of that class. Thus, if a query for the "camera" permission with no deviceId returns "granted", the client knows that there will never be a permission prompt for a camera, and if "denied" is returned, it knows that no getUserMedia request for a camera will succeed.

If a permission state is present for access to some, but not all, cameras, a query without the deviceId will return "prompt".

Note that a "granted" permission is no guarantee that getUserMedia will succeed. It only guarantees that the user will not be prompted for permission. There are many other things (such as constraints or the camera being in use) that can cause getUserMedia to fail.

extra permission data type
A list of deviceId values for the devices the user has granted access to.
permission result type
TODO
permission query algorithm
TODO
permission request algorithm
TODO
permission revocation algorithm
TODO: Stop playing/recording data?

The "device-info" permission controls access to names and capabilities of input and output devices.

A successful call to the getUserMedia function of [GETUSERMEDIA] MUST cause permission to be granted for the returned devices, and MAY cause other permissions to be granted.

Stopping a MediaStreamTrack MAY cause permission to be revoked for the associated device.

10.6. Background Sync

The "background-sync" permission is the permission associated with the usage of [web-background-sync].

10.7. Persistent Storage

The "persistent-storage" permission allows an origin to make its site storage unit contain a persistent box. "persistent-storage" is a boolean feature.

If a realm with origin O requests permission to use {name: "persistent-storage"} and that algorithm returns "granted", then {name: "persistent-storage"}'s permission state must be "granted" in all realms with origin O until the UA receives new information about the user’s intent.

11. Examples

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.

navigator.permissions.query({ name: "geolocation" }).then(({ state }) => {
  switch (state) {
    case "granted":
      showLocalNewsWithGeolocation();
      break;
    case "prompt":
      showButtonToEnableLocalNews();
      break;
    default:
      // Don’t do anything if the permission was denied.
      break;
  }
});

This example is using the "notifications" permission for a chat application to show a notification button depending on the permission state.

function updateNotificationButton(state) {
  document.getElementById('chat-notification-button')
    .disabled = (state === 'denied');
}

navigator.permissions.query({ name: 'notifications' }).then((result) => {
  updateNotificationButton(result.state);
  result.addEventListener('change', () => {
    updateNotificationButton(result.state);
  });
});

This example is checking whether the page has the "geolocation" and the "notifications" permissions using Promise.all.

Promise.all([
  navigator.permissions.query({ name: "geolocation" }),
  navigator.permissions.query({ name: "notifications" })
])
.then(([{ state: geoState }, { state: notifState }]) => {
  console.log("Geolocation permission state is:", geoState);
  console.log("Notifications permission state is:", notifState);
});

This example is checking the permission state of the available cameras.

navigator.mediaDevices
  .enumerateDevices()
  .then(devices => {
    return Promise.all(devices
      // filter on video inputs
      .filter(({ kind }) => kind === "videoinput")
      // map to query object
      .map(({ deviceId }) => ({ name: "camera", deviceId }))
      // map to query promise
      .map(queryObj => navigator.permissions.query(queryObj))
    );
  })
  // log the state or each camera
  .then(results => results.forEach(
    ({ state }, i) => console.log(Camera ${i}: "${state}")
  ))
  .catch(
    err => console.error(err.stack)
  );

Acknowledgments

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.

Conformance

Document conventions

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.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/
[FileAPI]
Marijn Kruisselbrink; Arun Ranganathan. File API. 11 September 2019. WD. URL: https://www.w3.org/TR/FileAPI/
[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://tools.ietf.org/html/rfc2119
[UIEVENTS]
Gary Kacmarcik; Travis Leithead; Doug Schepers. UI Events. 30 May 2019. WD. URL: https://www.w3.org/TR/uievents/
[WEBIDL]
Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

Informative References

[AUDIO-OUTPUT]
Justin Uberti; Guido Urdaneta; youenn fablet. Audio Output Devices API. 15 February 2021. CR. URL: https://www.w3.org/TR/audio-output/
[geolocation-API]
Andrei Popescu. Geolocation API Specification 2nd Edition. 8 November 2016. REC. URL: https://www.w3.org/TR/geolocation-API/
[GETUSERMEDIA]
Cullen Jennings; et al. Media Capture and Streams. 15 February 2021. CR. URL: https://www.w3.org/TR/mediacapture-streams/
[NOTIFICATIONS]
Anne van Kesteren. Notifications API Standard. Living Standard. URL: https://notifications.spec.whatwg.org/
[PUSH-API]
Peter Beverloo; Martin Thomson. Push API. 4 February 2020. WD. URL: https://www.w3.org/TR/push-api/
[WEB-BACKGROUND-SYNC]
Web Background Synchronization. cg-draft. URL: https://wicg.github.io/background-sync/spec/
[WEB-BLUETOOTH]
Jeffrey Yasskin. Web Bluetooth. Draft Community Group Report. URL: https://webbluetoothcg.github.io/web-bluetooth/
[WEBMIDI]
Chris Wilson; Jussi Kalliokoski. Web MIDI API. 17 March 2015. WD. URL: https://www.w3.org/TR/webmidi/

IDL Index

dictionary PermissionDescriptor {
  required PermissionName name;
};

enum PermissionState {
  "granted",
  "denied",
  "prompt",
};

[Exposed=(Window,Worker)]
interface PermissionStatus : EventTarget {
  readonly attribute PermissionState state;
  attribute EventHandler onchange;
};

[Exposed=(Window)]
partial interface Navigator {
  readonly attribute Permissions permissions;
};

[Exposed=(Worker)]
partial interface WorkerNavigator {
  readonly attribute Permissions permissions;
};

[Exposed=(Window,Worker)]
interface Permissions {
  Promise<PermissionStatus> query(PermissionDescriptor permissionDesc);

  Promise<PermissionStatus> request(PermissionDescriptor permissionDesc);

  Promise<PermissionStatus> revoke(PermissionDescriptor permissionDesc);
};

enum PermissionName {
  "geolocation",
  "notifications",
  "push",
  "midi",
  "camera",
  "microphone",
  "speaker",
  "device-info",
  "background-sync",
  "bluetooth",
  "persistent-storage",
};

dictionary PushPermissionDescriptor : PermissionDescriptor {
  boolean userVisibleOnly = false;
};

dictionary MidiPermissionDescriptor : PermissionDescriptor {
  boolean sysex = false;
};

dictionary DevicePermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
};

Issues Index

Safari is the only known UA that returns different results from this algorithm for different settings objects with the same origin. We should test which of the several possible settings objects it uses.
On browsers that don’t store permissions persistently within an environment settings object, this will always return "prompt", but still show the user an unnecessary prompt. That may mean that no permissions should use the boolean permission request algorithm, since it can never return an appropriate object-capability.