Getting Browser User Permission with the Permissions API
Tags: javascript, webdev, programming, beginners
Published: 2021-01-22 02:33:04

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

We have to get user consent when we want to do anything that changes the user experience. For example, we need to get user permission to show notifications or access their hardware.

Modern browsers are standardized in how permissions are obtained. It’s all in the Permissions API.

APIs that rely on the Permissions API for permissions include the Clipboard API, Notifications API, Push API, and Web MIDI API.

The `navigator` object has the `permissions` property in both the standard browser and worker contexts. It gives us a way to get the permissions. However, the way we request permissions is different for each API.

This API is experimental so check if the browsers you target are supported.

### Querying Permissions

The `navigation.permissions` object lets us query permissions set with the `query` method.

It returns a promise which gets us the state of the permission. For example, we can write the following to check for permission for the geolocation API:

```
(async () => {
  const result = await navigator.permissions.query({
    name: 'geolocation'
  });
  console.log(result.state);
})();
```

The possible values for `result.state` are `'granted'`, `'denied'`, or `'prompt'`.

There’s also one for Web Workers that do the same thing.

The object that we passed into the `query` method is the permission descriptor object, which has the following properties:

*   `name` — name of the API which we want to get the permission for. Firefox only supports `geolocation`, `notifications`, `push`, and `persistent-storage`
*   `userVisibleOnly` — indicates whether we want to show notification for every message or be able to send silent push notifications. Default value is `false` .
*   `sysex` — applies to MIDI only. Indicates whether we need to receive system exclusive messages. Default value is `false` .

### Requesting Permission

Requesting permission is different between APIs. For example, the Geolocation API will show a prompt for permission when we call `getCurrentPosition()` as follows:

```
navigator.geolocation.getCurrentPosition((position) => {
  console.log('Geolocation permissions granted');
  console.log(`Latitude: ${position.coords.latitude}`);
  console.log(`Longitude: ${position.coords.longitude}`);
});
```

The Notifications API has a `requestPermission` method to request permissions:

```
Notification.requestPermission((result) => {
  console.log(result);
});
```

### Watching for Permission Changes

The `navigator.permissions.query` promise resolves to a `PermissionStatus` object. We can use it to set an `onchange` event handler function to watch for permission changes.

For example, we can expand on this example to add an event handler function to watch for changes for the permission of the Geolocation API:

```
(async () => {
  const result = await navigator.permissions.query({
    name: 'geolocation'
  });
  console.log(result.state);
})();
```

We can write:

```
(async () => {
  const permissionStatus = await navigator.permissions.query({
    name: 'geolocation'
  });
  permissionStatus.onchange = () => {
    console.log(permissionStatus.state);
  }
})();
```

The `permissionStatus.state` will have the permission for the Geolocation API.

It’ll log whenever the permission changes, such as when we change the permission setting in the browser.

### Revoking Permissions

We can revoke permission by using the `revoke` method.

To call it, we can access it from the `navigator.permissions` object as follows:

```
navigator.permissions.revoke(descriptor);
```

Where `descriptor` is the permission descriptor which we described above.

It returns a Promise that resolves with the permission status object indicating the result of the request.

This method throws a TypeError if getting the permission descriptor failed or the permission doesn’t exist or is unsupported by browsers.

The `name` property of the permission descriptor can accept one of the following values `'geolocation'`, `'midi'`, `'notifications'`, and `'push'`.

Other properties remain the same as the `query` method.

For example, we can use it by writing:

```
(async () => {
  const permissionStatus = await navigator.permissions.revoke({
    name: 'geolocation'
  });
  console.log(permissionStatus);
})();
```

Note that we’ve to set `dom.permissions.revoke.enable` to `true` in Firefox 51 or later to use this method. It’s not enabled in Chrome.

The Permissions API lets us check and revoke browser permissions in a uniform way.

Requesting permissions are different for each API. This isn’t changing any time soon.

This is an experimental API, so using it in production is probably premature.