Permission-Policy example

Complete guide to implementing Permissions-Policy (formerly Feature-Policy) headers for controlling browser features and enhancing privacy.

What is Permissions-Policy?

Permissions-Policy allows you to control which browser features and APIs can be used on your website, preventing misuse of powerful features like camera, microphone, geolocation, etc.

Basic Syntax

Header always set Permissions-Policy "feature-name=(allowed-origins)"

Common Features

Deny All Features

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

Allow for Self Only

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

Allow for Specific Domains

Permissions-Policy: camera=(self "https://trusted-domain.com")

Complete Feature List

Sensors & Hardware

Permissions-Policy: accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=()

Media Devices

Permissions-Policy: camera=(), microphone=(), speaker-selection=(), display-capture=()

Location & Motion

Permissions-Policy: geolocation=(), screen-wake-lock=()

Payments & Identity

Permissions-Policy: payment=(), identity-credentials-get=()

Connectivity

Permissions-Policy: usb=(), serial=(), bluetooth=(), hid=()

Other Features

Permissions-Policy: fullscreen=(self), picture-in-picture=(self), autoplay=(self)

Real-World Examples

Strict Security (Block Everything)

Header always set Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"

Standard Website

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

Video Conferencing Site

Permissions-Policy: camera=(self), microphone=(self), display-capture=(self), fullscreen=(self), speaker-selection=(self)

E-Commerce Site

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

Gaming/VR Site

Permissions-Policy: fullscreen=(self), gamepad=(self), xr-spatial-tracking=(self), accelerometer=(self), gyroscope=(self)

Feature Descriptions

Feature Description
accelerometer Device acceleration sensor
ambient-light-sensor Ambient light detection
autoplay Autoplay media
camera Camera access
display-capture Screen sharing/capture
fullscreen Fullscreen mode
geolocation GPS location
gyroscope Device rotation sensor
magnetometer Compass sensor
microphone Microphone access
midi MIDI device access
payment Payment Request API
picture-in-picture PiP video mode
speaker-selection Audio output selection
usb USB device access
web-share Web Share API
xr-spatial-tracking VR/AR tracking

Implementation

Apache (.htaccess)

<IfModule mod_headers.c>
    Header always set Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
</IfModule>

Nginx

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

IIS (web.config)

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Permissions-Policy" value="accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

Testing

Check in Browser DevTools

  1. Open DevTools (F12)
  2. Go to Console tab
  3. Attempt to use a blocked feature
  4. You'll see permission denied errors

Test Geolocation

navigator.geolocation.getCurrentPosition(
    position => console.log(position),
    error => console.error('Blocked by Permissions-Policy')
);

Test Camera

navigator.mediaDevices.getUserMedia({ video: true })
    .then(stream => console.log('Camera allowed'))
    .catch(error => console.error('Camera blocked'));

Legacy Feature-Policy

Older browsers used Feature-Policy instead:

Header always set Feature-Policy "camera 'none'; microphone 'none'; geolocation 'none'"

Note: Use both headers for maximum compatibility:

Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Feature-Policy "camera 'none'; microphone 'none'; geolocation 'none'"

Iframe Integration

Control features in embedded iframes:

<iframe src="https://example.com" allow="camera; microphone"></iframe>

Best Practices

  1. Block Unnecessary Features - Only allow what you need
  2. Be Specific - Use self instead of * when possible
  3. Test Thoroughly - Ensure legitimate features still work
  4. Document Allowed Features - Keep track of why each feature is allowed
  5. Review Regularly - Remove permissions for deprecated features

Common Configurations

Blog/News Site

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

Corporate Website

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

Social Media Platform

Permissions-Policy: camera=(self), microphone=(self), geolocation=(self), fullscreen=(self), picture-in-picture=(self)

Security Headers Combination

Combine with other security headers:

Header always set Content-Security-Policy "default-src 'self'"
Header always set Permissions-Policy "camera=(), microphone=()"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Strict-Transport-Security "max-age=31536000"

Checking Your Configuration

Test your headers at:

Additional Resources

Related Security Headers

User