Back to Learn

Permissions-Policy Header Guide | NOC.org

What Is Permissions-Policy?

Permissions-Policy is an HTTP security header that allows website owners to control which browser features and APIs can be used on their pages and by embedded third-party content. By setting this header, you can explicitly enable or disable access to powerful browser capabilities such as the camera, microphone, geolocation, payment APIs, autoplay, and many others.

This header was originally introduced as Feature-Policy and was renamed to Permissions-Policy in 2020 to better reflect its purpose. The rename also came with a syntax change — Feature-Policy used a space-separated list format, while Permissions-Policy uses a structured header format with parentheses and equals signs. Most modern browsers now support the Permissions-Policy syntax, though some older browsers still recognize Feature-Policy.

The primary benefit of Permissions-Policy is reducing your site's attack surface. Even if your site does not use the camera or microphone, a malicious script injected via XSS or a compromised third-party resource could attempt to access these features. By disabling features you do not need, you create a policy boundary that prevents abuse regardless of what code runs on your page.

How Permissions-Policy Works

Permissions-Policy operates on a per-feature basis. For each feature, you specify an allowlist that defines which origins are permitted to use that feature. The allowlist can include:

  • * — All origins are allowed to use the feature.
  • self — Only the current origin (your site) can use the feature.
  • () — The feature is completely disabled for all origins, including your own.
  • Specific origins — Only the listed origins can use the feature, such as "https://trusted-cdn.com".

Syntax and Format

The Permissions-Policy header uses structured header syntax where each directive is a key-value pair separated by commas:

# Disable camera and microphone entirely
Permissions-Policy: camera=(), microphone=()

# Allow geolocation only for same origin
Permissions-Policy: geolocation=(self)

# Allow payment API for self and a specific payment provider
Permissions-Policy: payment=(self "https://payments.example.com")

# Multiple directives in one header
Permissions-Policy: camera=(), microphone=(), geolocation=(self), autoplay=(self), payment=(self "https://payments.example.com")

Old Feature-Policy Syntax (Deprecated)

For reference, the older Feature-Policy header used a different syntax:

# Old Feature-Policy syntax (deprecated)
Feature-Policy: camera 'none'; microphone 'none'; geolocation 'self'

# Equivalent Permissions-Policy syntax (current)
Permissions-Policy: camera=(), microphone=(), geolocation=(self)

If you are maintaining legacy configurations, note that 'none' in Feature-Policy maps to () in Permissions-Policy, and 'self' maps to (self).

Common Feature Directives

Camera and Microphone

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

Controls access to the device camera and microphone. Disabling these features prevents any script on your page (including third-party scripts) from requesting camera or microphone access. This is especially important for sites that embed third-party ads, widgets, or analytics scripts, as a compromised script could attempt to activate the camera or microphone without the user's knowledge.

Geolocation

Permissions-Policy: geolocation=(self)

Controls the Geolocation API. Setting this to (self) allows your own pages to use geolocation (with the user's permission prompt) while preventing embedded iframes from third-party origins from requesting location data. Completely disabling it with () is appropriate for sites that never need location data.

Autoplay

Permissions-Policy: autoplay=(self)

Controls whether media can autoplay on the page. This is useful for preventing embedded third-party content (such as ads or social media embeds) from autoplaying video or audio, which can be disruptive to users and increase bandwidth usage.

Payment

Permissions-Policy: payment=(self "https://payments.stripe.com")

Controls access to the Payment Request API. If your site processes payments through a specific provider, you can restrict the payment API to your origin and the payment provider's origin, preventing any other embedded content from initiating payment requests.

Fullscreen

Permissions-Policy: fullscreen=(self)

Controls whether the Fullscreen API can be used. Restricting this to your own origin prevents embedded content from taking over the user's screen, which could be used for phishing attacks or deceptive interfaces.

Display Capture and Screen Wake Lock

Permissions-Policy: display-capture=(), screen-wake-lock=(self)

Display capture controls access to screen sharing APIs, while screen wake lock prevents the screen from dimming or locking. Disabling display capture prevents any scripts from initiating screen recording. Screen wake lock should be limited to your own origin if needed for media playback or presentation features.

USB, Bluetooth, and Serial

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

These directives control access to hardware APIs that allow web pages to interact with USB devices, Bluetooth peripherals, and serial ports. Unless your application specifically needs hardware access, these should be disabled to prevent supply-chain attacks through compromised scripts.

Permissions-Policy in Iframes

Permissions-Policy interacts closely with the allow attribute on iframe elements. Even if a parent page's Permissions-Policy allows a feature, the iframe must also be explicitly granted permission through the allow attribute:

<!-- Allow the iframe to use geolocation and camera -->
<iframe src="https://maps.example.com" allow="geolocation; camera"></iframe>

<!-- Allow autoplay for an embedded video -->
<iframe src="https://video.example.com" allow="autoplay"></iframe>

<!-- Deny all features to the iframe -->
<iframe src="https://untrusted.example.com" allow=""></iframe>

The effective permissions for an iframe are the intersection of the parent page's Permissions-Policy and the iframe's allow attribute. If either denies a feature, the feature is unavailable in the iframe. This layered approach ensures that even if a developer forgets to restrict iframe permissions, the site-wide Permissions-Policy acts as a safety net.

Recommended Default Policy

For most websites, a good starting point is to disable all features you do not use and restrict the rest to your own origin:

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=(), serial=(), autoplay=(self), fullscreen=(self), display-capture=()

Then selectively open features as needed. This "deny by default" approach minimizes your attack surface and ensures you are explicitly aware of every browser feature your site uses.

Server Configuration

Apache

# In .htaccess or virtual host config
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), autoplay=(self), fullscreen=(self)"

Nginx

# In server block
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), autoplay=(self), fullscreen=(self)" always;

Deprecated: Expect-CT Header

While discussing Permissions-Policy and its evolution from Feature-Policy, it is worth addressing another deprecated security header: Expect-CT.

Expect-CT was introduced to enforce Certificate Transparency (CT) — a system that requires Certificate Authorities to publicly log all SSL/TLS certificates they issue. The purpose was to detect misissued or fraudulent certificates. The header allowed site owners to instruct browsers to verify that their certificates appeared in public CT logs:

# The deprecated Expect-CT header
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/ct-report"

As of June 2021, Certificate Transparency is enforced by default in all major browsers. Chrome, Firefox, Safari, and Edge all require certificates to include Signed Certificate Timestamps (SCTs) from CT logs. Since CT is now universally enforced at the browser level, the Expect-CT header serves no purpose and has been deprecated.

Key points about Expect-CT:

  • No longer needed: All modern browsers enforce CT automatically. The header adds no additional security.
  • Chrome removed support: Chrome 107 (October 2022) removed Expect-CT support entirely.
  • No harm in keeping it: If your site currently sends the Expect-CT header, it is harmless — browsers that do not support it simply ignore it. However, there is no benefit to adding it to new deployments.
  • Focus on proper certificate management: Instead of relying on Expect-CT, ensure your Certificate Authority issues CT-compliant certificates (virtually all CAs do today) and monitor CT logs directly through services like crt.sh or Google's CT search.

Testing Permissions-Policy

# Check the header with curl
curl -I https://example.com | grep -i permissions-policy

# Expected output
Permissions-Policy: camera=(), microphone=(), geolocation=(), autoplay=(self)

Browser developer tools also show Permissions-Policy violations in the console. If a script attempts to use a feature that is denied by the policy, you will see a message such as: "Permissions policy violation: camera is not allowed in this document."

Chrome DevTools has a dedicated "Application" panel where you can view the active permissions policy for the current page under the "Permissions Policy" section.

Summary

Permissions-Policy (formerly Feature-Policy) is a powerful security header that reduces your site's attack surface by controlling which browser features are available to your pages and to embedded third-party content. Disable features you do not use, restrict features you do use to trusted origins, and use the iframe allow attribute for granular control over embedded content. The deprecated Expect-CT header is no longer necessary since Certificate Transparency is now enforced by default in all browsers. Combined with CSP and other security headers, Permissions-Policy forms a critical part of a defense-in-depth strategy. See our security header configuration guide for complete implementation details.

Need help managing your security headers? Explore NOC.org plans to get started.

Improve Your Websites Speed and Security

14 days free trial. No credit card required.