Permissions-Policy HTTP header
How the Permissions-Policy header controls access to browser features like camera, microphone and geolocation, its syntax, and how to set it in Apache and PHP.
The Permissions-Policy header lets a site declare which browser features and APIs are allowed to be used, and by whom. It controls access to things like the camera, microphone and geolocation, along with a long list of other capabilities, both for your own pages and for anything you embed in an iframe.
It was previously called Feature-Policy, and while some older browsers still recognise that name, Permissions-Policy is the current standard and the one to use.
Permissions-Policy: geolocation=(), camera=(), microphone=()
That example switches off geolocation, camera and microphone access entirely. Even if a script on the page, or a third-party embed, tries to use one of them, the browser refuses.
The syntax
Each directive is a feature name followed by an allowlist in brackets:
camera=()- an empty list disables the feature for everyone.geolocation=(self)- allow it only for your own origin.fullscreen=(self "https://embed.example.com")- allow your origin and one named third party.microphone=*- allow it everywhere, including embeds. Rarely what you want.
The safe default is to disable the features you do not use, so that a compromised script or a questionable embed cannot quietly reach for the camera or the visitor's location. Set the handful of features you do need to self and turn the rest off.
It rounds out the set alongside Content-Security-Policy and the other web application security headers.
How to set Permissions-Policy in Apache
<IfModule mod_headers.c>
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
</IfModule>
How to set Permissions-Policy in PHP
header('Permissions-Policy: geolocation=(), camera=(), microphone=()');
Setting it on AWS CloudFront
On a static site served through CloudFront the header belongs on the distribution rather than a web server. A response headers policy is the tidiest way to do it, declaring Permissions-Policy next to your other security headers so CloudFront attaches them to every response without any code. Where you want the value to vary, a CloudFront Function on the viewer response can rewrite it in a few lines of JavaScript, leaving Lambda@Edge for the heavier logic a lightweight function cannot do.