How Permissions Policy Restricts JavaScript Features
The Permissions Policy HTTP header allows website owners to explicitly enable, restrict, or disable access to sensitive browser features and hardware APIs for both the main document and embedded third-party frames. This article explains how the Permissions Policy header functions, breaks down its syntax and directives, demonstrates how it enforces restrictions against JavaScript execution, and details the security benefits it offers against unauthorized API usage.
What is the Permissions Policy Header?
Permissions Policy (formerly known as Feature Policy) is a standard HTTP response header that defines a security contract between a web server and the client browser. By declaring a set of directives, a server informs the browser which powerful web platform APIs—such as geolocation, camera access, microphone inputs, or autoplay—are permitted to run in the current context.
When a browser receives this header, it configures internal permission registries before executing page scripts. If a script attempts to invoke a disabled API, the browser immediately blocks execution at the platform level, preventing unauthorized access regardless of user settings or script privileges.
How Permissions Policy Interacts with JavaScript
Permissions Policy enforces restrictions deterministically at the browser runtime level, altering how standard JavaScript APIs behave:
- Immediate Promise Rejections: APIs that rely on
JavaScript Promises fail automatically. For example, invoking
navigator.mediaDevices.getUserMedia()when thecamerapolicy is disabled will immediately reject with aNotAllowedErrororSecurityErrorDOMException without prompting the user. - Synchronous Failures: Synchronous properties or
methods associated with blocked features either return
false, returnundefined, or throw an error. For instance,document.requestFullscreen()will fail and trigger afullscreenerrorevent. - Integration with the Permissions API: Scripts can
inspect policy restrictions programmatically using
navigator.permissions.query(). If a feature is disabled by Permissions Policy, the permission state will report asdenied, allowing developers to write fallback logic.
// Example: Querying the state of an API restricted by Permissions Policy
navigator.permissions.query({ name: 'geolocation' }).then((result) => {
if (result.state === 'denied') {
console.warn('Geolocation is blocked by Permissions Policy.');
}
});Syntax and Directive Structure
The Permissions Policy header uses a structured header syntax consisting of feature names assigned to allowlists:
Permissions-Policy: <feature>=(<allowlist>), <feature>=(<allowlist>)
Allowlist Values
()(Empty): Disables the feature entirely for all contexts, including the top-level origin and all iframes.self: Restricts the feature to the origin of the document serving the header.*: Allows the feature for the current origin and any nested browsing context."https://example.com": Explicitly delegates permission to a specific origin.
Example Header Configurations
Block access entirely:
Permissions-Policy: camera=(), microphone=(), geolocation=()In this configuration, any JavaScript call targeting the camera, microphone, or geolocation fails immediately across the entire page and all child frames.
Allow only for the primary origin:
Permissions-Policy: payment=(self), fullscreen=(self)Only scripts hosted on the same origin as the top-level document can use the Payment Request API or enter fullscreen mode.
Delegate to specific third parties:
Permissions-Policy: camera=(self "https://trusted-partner.com")Camera access is available to the main site and specifically authorized iframes hosted on
trusted-partner.com.
Restricting Embedded Content (iFrames)
Permissions Policy provides strict control over third-party scripts
loaded through <iframe> elements. By default,
powerful features disabled in the top-level document’s HTTP header
cannot be enabled by an iframe, even if the iframe attempts to override
the policy.
To grant an allowed feature to an iframe, the parent document must
explicitly pass permission using the iframe’s allow
attribute:
<!-- Grants camera access to an embedded partner, assuming the HTTP header permits it -->
<iframe src="https://trusted-partner.com/meeting" allow="camera"></iframe>If the parent document’s HTTP header disables the feature with
camera=(), any allow="camera" attribute
defined on an iframe will be ignored, maintaining absolute enforcement
from the server’s policy.
Security Benefits
Implementing the Permissions Policy header provides several core security advantages:
- Mitigating Cross-Site Scripting (XSS) Impact: If an attacker injects malicious JavaScript via an XSS vulnerability, they cannot access sensitive hardware like webcams or physical location data if those APIs are disabled via the policy.
- Restricting Rogue Third-Party Dependencies: Third-party analytics, ad tags, or external widgets are prevented from silently tracking users, polling device sensors, or launching intrusive APIs.
- Minimizing Unintended Resource Consumption: Blocking heavy features such as synchronous XMLHttpRequests, autoplay, or CPU-intensive sensors improves overall client-side performance and battery life.