Using the Permissions API

This is an experimental technology
Because this technology's specification has not stabilized, check the compatibility table for usage in various browsers. Also note that the syntax and behavior of an experimental technology is subject to change in future versions of browsers as the specification changes.

This article provides a basic guide to using the W3C Permissions API, which provides a programmatic way to query the status of API permissions attributed to the current context.

The trouble with asking for permission...

Let's face it, permissions on the Web are a necessary evil, and they are not much fun to deal with as developers.

Historically, different APIs handle their own permissions inconsistently — for example the Notifications API allows for explicit checking of permission status and requesting permission, whereas the Geolocation API doesn't (which causes problems if the user denied the initial permission request, as we'll see below.)

The Permissions API provides the tools to allow developers to implement a better user experience as far as permissions are concerned. For example, it can query whether permission to use a particular API is granted or denied, and specifically request permission to use an API.

At the moment, implementation of the API is at an early stage:

  • It can only be found in Chrome 44+ and Firefox 43+.
  • The only supported method right now is Permissions.query, which queries permission status.
  • The only two APIs currently recognised by the Permissions API in Chrome are Geolocation and Notification, with firefox also recognising Push and WebMIDI.

More features will be added as time progresses.

A simple example

For this article, we have put together a simple demo called Location Finder. It uses Geolocation to query the user's current location and plot it out on a Google Map:

Screenshot showing a map of Greenfield, UK.

You can run the example live, or view the source code on Github. Most of the code is simple and unremarkable — below we'll just be walking through the Permissions API-related code, so check the code yourself if you want to study any of the other parts.

Accessing the Permissions API

The Navigator.permissions property has been added to the browser to allow access to the Permissions object. This object will include methods for querying, requesting and revoking permissions, although currently it only contains Permissions.query(); see below.

Querying permission state

In our example, the Permissions functionality is handled by one function — handlePermission(). This starts off by querying the permission status using Permissions.query(). Depending on the state property of the  PermissionStatus object returned when the promise resolves, it reacts differently:

  • granted: The "Enable Geolocation" button is hidden, as it is not needed if Geolocation is active.
  • prompt: The "Enable Geolocation" button is hidden, as it is not needed if the user is being prompted to grant permission for Geolocation. The Geolocation.getCurrentPosition function is then run, which prompts the user for permission; it runs the revealPosition() function if permission is granted (which shows the map), or the positionDenied() function if permission is denied (which makes the "Enable Geolocation" button appear.)
  • denied: The "Enable Geolocation" button is revealed (this code needs to be here too, in case the permission state is already set to denied for this origin when the page is first loaded.)
function handlePermission() {
  navigator.permissions.query({name:'geolocation'}).then(function(result) {
    if (result.state == 'granted') {
      report(result.state);
      geoBtn.style.display = 'none';
    } else if (result.state == 'prompt') {
      report(result.state);
      geoBtn.style.display = 'none';
      navigator.geolocation.getCurrentPosition(revealPosition,positionDenied,geoSettings);
    } else if (result.state == 'denied') {
      report(result.state);
      geoBtn.style.display = 'inline';
    }
    result.onchange = function() {
      report(result.state);
    }
  });
}

function report(state) {
  console.log('Permission ' + state);
}

handlePermission();

Permission descriptors

The Permissions.query() method takes a PermissionDescriptor dictionary as a parameter — this contains the name of the API you are interested in. Some APIs have more complex PermissionDescriptors containing additional information, which inherit from the default PermissionDescriptor. For example, the PushPermissionDescriptor will be intended to also contain a boolean that specifies if userVisibleOnly is true or false.

Revoking permissions

As of Firefox 47, you can now revoke existing permissions, using the  Permissions.revoke() method. This works in exactly the same way as the Permissions.query() method, except that it causes an existing permission to be reverted back to its default state when the promise successfully resolves (which is usually prompt.) See the following code in our demo:

var revokeBtn = document.querySelector('.revoke');

  ...

revokeBtn.onclick = function() {
  revokePermission();
}

  ...

function revokePermission() {
  navigator.permissions.revoke({name:'geolocation'}).then(function(result) {
    report(result.state);
  });
}

Responding to permission state changes

You'll notice that there is an onchange event handler in the code above, attached to the PermissionStatus object — this allows us to respond to any changes in the permission status for the API we are interested in. At the moment we are just reporting the change in state.

Conclusion and future work

At the moment this doesn't offer much more than what we had already. If we choose to never share our location from the permission prompt (deny permission), then we can't get back to the permission prompy without using the browser menu options:

  • Firefox: Tools > Page Info > Permissions > Access Your Location. Select Always Ask.
  • Chrome: Hamburger Menu > Settings > Show advanced settings. In the Privacy section, click Content Settings. In the resulting dialog, find the Location section and select Ask when a site tries to... . Finally, click Manage Exceptions and remove the permissions you granted to the sites you are interested in.

However, future additions to browser functionality should provide the request() method, which will allow us to programatically request permissions, any time we like. These should hopefully be available soon.

Document Tags and Contributors

 Contributors to this page: dharkness, chrisdavidmills, teoli
 Last updated by: dharkness,