Permissions-Policy (formerly Feature-Policy)

HTTP header that controls browser features and APIs available to a webpage to enhance security and privacy.

What is Permissions-Policy?

Permissions-Policy (formerly known as Feature-Policy) is an HTTP security header that allows website owners to control which browser features and APIs can be used by a webpage. This header provides granular control over powerful browser capabilities, enabling developers to enhance security, privacy, and performance by restricting access to potentially sensitive features.

The header works by specifying a policy that defines which origins (if any) can use specific browser features, such as geolocation, camera, microphone, fullscreen, and more.

Header Syntax

The Permissions-Policy header uses the following syntax:

Permissions-Policy: <feature>=<allowlist>
Permissions-Policy: <feature>=(), <feature>=<allowlist>

Where:

  • <feature> is the browser feature being controlled
  • <allowlist> specifies which origins are allowed to use the feature

Evolution from Feature-Policy to Permissions-Policy

The header was originally named Feature-Policy but was renamed to Permissions-Policy to better reflect its purpose and align with the Permissions API. The functionality remains largely the same, but the syntax and some feature names have been updated.

Key changes:

  • Header name changed from Feature-Policy to Permissions-Policy
  • Some feature names were updated for consistency
  • Improved syntax for better readability

Common Features and Directives

Permissions-Policy provides control over numerous browser features:

FeatureDescriptionExample Policy
accelerometerControls access to accelerometer sensoraccelerometer=()
ambient-light-sensorControls access to ambient light sensorambient-light-sensor=('self')
autoplayControls automatic media playbackautoplay=('self' https://example.com)
cameraControls access to cameracamera=()
display-captureControls screen sharing capabilitiesdisplay-capture=('self')
document-domainControls ability to set document.domaindocument-domain=()
encrypted-mediaControls Encrypted Media Extensions (EME)encrypted-media=('self')
fullscreenControls fullscreen modefullscreen=()
geolocationControls access to geolocationgeolocation=('self' https://trusted.com)
gyroscopeControls access to gyroscope sensorgyroscope=()
magnetometerControls access to magnetometer sensormagnetometer=()
microphoneControls access to microphonemicrophone=()
midiControls access to MIDI devicesmidi=()
paymentControls Payment Request APIpayment=('self')
picture-in-pictureControls picture-in-picture videopicture-in-picture=()
publickey-credentials-getControls Web Authentication APIpublickey-credentials-get=()
screen-wake-lockControls screen wake lockscreen-wake-lock=()
sync-xhrControls synchronous XHR requestssync-xhr=()
usbControls WebUSB APIusb=()
web-shareControls Web Share APIweb-share=('self')
xr-spatial-trackingControls WebXR device APIxr-spatial-tracking=()

Policy Syntax Examples

Disable a feature completely:

Permissions-Policy: geolocation=()

Allow a feature for the current origin:

Permissions-Policy: camera=('self')

Allow a feature for specific origins:

Permissions-Policy: microphone=('self' https://trusted-audio.com)

Multiple features in one header:

Permissions-Policy: geolocation=(), camera=(), microphone=('self')

Security and Privacy Benefits

Enhanced security:

  • Prevents malicious scripts from accessing sensitive device features
  • Reduces attack surface by disabling unnecessary browser APIs
  • Mitigates risks from third-party scripts and iframes

Improved privacy:

  • Prevents unauthorized access to location, camera, microphone, etc.
  • Limits tracking capabilities through sensor data
  • Gives users more control over their data

Performance optimization:

  • Disables resource-intensive features when not needed
  • Reduces battery consumption on mobile devices
  • Prevents background processes from using sensors

Best Practices

  1. Follow the principle of least privilege - disable all features by default and only enable what's necessary
  2. Be specific with allowlists - avoid using * which allows all origins
  3. Combine with other security headers for comprehensive protection:
  4. Test policies thoroughly - ensure they don't break required functionality
  5. Regularly review and update policies as your application evolves

Example Implementations

HTTP Response Header:

Permissions-Policy: geolocation=(), camera=(), microphone=(), accelerometer=(), gyroscope=(), magnetometer=(), payment=(), usb=()

Web Server Configuration Examples:

Apache (.htaccess):

Header set Permissions-Policy "geolocation=(), camera=(), microphone=(), accelerometer=(), gyroscope=(), magnetometer=(), payment=(), usb=()"

Nginx:

add_header Permissions-Policy "geolocation=(); camera=(); microphone=(); accelerometer=(); gyroscope=(); magnetometer=(); payment=(); usb=()";

Express.js (Node.js):

app.use((req, res, next) => {
  res.setHeader('Permissions-Policy', "geolocation=(), camera=(), microphone=(), accelerometer=(), gyroscope=(), magnetometer=(), payment=(), usb=()");
  next();
});

Common Use Cases

  1. Privacy-focused websites: Disable all unnecessary sensors and device access
  2. E-commerce platforms: Control payment and geolocation features
  3. Corporate intranets: Restrict camera and microphone access in sensitive environments
  4. Educational platforms: Manage screen sharing and device access in virtual classrooms
  5. Healthcare applications: Secure access to sensitive features in medical apps
  6. Government websites: Enhance citizen privacy by limiting tracking capabilities

Browser Support

Permissions-Policy is supported in modern browsers:

  • Chrome 60+ (as Feature-Policy), 88+ (as Permissions-Policy)
  • Firefox 74+ (partial support)
  • Edge 88+
  • Safari 14+ (partial support)

Migration from Feature-Policy

To migrate from Feature-Policy to Permissions-Policy:

  1. Update the header name:
    - Feature-Policy: geolocation 'none'
    + Permissions-Policy: geolocation=()
    
  2. Update feature names (some features were renamed):
    - Feature-Policy: vibrate 'none'
    + Permissions-Policy: vibrate=()
    
  3. Update allowlist syntax:
    - Feature-Policy: camera 'self' https://trusted.com
    + Permissions-Policy: camera=('self' https://trusted.com)