The Private Network Access (PNA) for non-secure contexts deprecation trial is ending—implement the PNA permission prompt

Yifan Luo
Yifan Luo

Chrome 124 includes the Private Network Access permission to relax mixed content feature. There is an ongoing deprecation trial for sites that need more time to prepare for this change, however this trial ends with Chrome 126, expected to ship on Sep 4, 2024. This post explains the change, more about the design of the feature, how to migrate your current websites, and how to test your implementation.

What is changing?

To establish connections to devices on a private network that don't have globally unique names, and therefore cannot obtain TLS certificates, this feature introduces a new option to fetch() to declare a developers' intent to talk to such a device. This includes a new policy-controlled feature to gate each site's access to this capability, and new headers for the server's preflight response to provide additional metadata.

What is Private Network Access?

Private Network Access (PNA, formerly known as CORS-RFC1918 and briefly as Local Network Access) is a security feature that restricts the ability of websites to send requests to servers on private networks. This helps protect users and internal networks from potential attacks like Cross-Site Request Forgery (CSRF). Chrome has been gradually implementing PNA, and protection will be expanded in upcoming releases.

Why is a permission prompt needed?

Chrome 94 introduced a block on private network access from non-secure public websites. The ongoing Private Network Access from non-secure contexts deprecation trial has revealed challenges in migrating affected websites to HTTPS. A common concern is the difficulty of migrating private devices to HTTPS, leading to mixed content check violations.

To address this challenge, a new permission prompt was added under an origin trial from Chrome 120, and in stable from Chrome 124.

When is a permission prompt needed?

We planned to end the non-secure contexts deprecation trial a few milestones after the permission prompt feature became available. To ensure compatibility, you must migrate your public websites to HTTPS. If you cannot migrate your private server to HTTPS, the new permission prompt feature will let you relax mixed content checks.

A typical workflow for a Private Network Access request with permission prompt is as follows.

Trigger the permission prompt

Add the new targetAddressSpace attribute as a fetch option, then the request can skip the mixed content check.

fetch("http://router.local/ping", {
  targetAddressSpace: "private",

In accordance with the Private Network Access: introducing preflights, any private network request is preceded by a preflight request. This preflight request will include a new header, Access-Control-Request-Private-Network: true, and the corresponding response must include the header Access-Control-Allow-Private-Network: true.

To accommodate the new permission prompt, devices must incorporate two new response headers: Private-Network-Access-Name and Private-Network-Access-ID.

  • Private-Network-Access-ID: A 48-bit value presented as 6 hexadecimal bytes separated by colons.
  • Private-Network-Access-Name: A valid name as a string that matches the ECMAScript regular expression /^[a-z0-9_-.]+$/. The maximum length of the name is 248 UTF-8 code units.
Private-Network-Access-Name: "My Smart Toothbrush"
Private-Network-Access-ID: "01:23:45:67:89:0A"


You can check out the demo at:

You need to start your personal private server to use the demo website. The private server should respond with HTTP header Access-Control-Allow-Private-Network: true, along with server specified headers Private-Network-Access-ID and Private-Network-Access-Name. If everything is set correctly, the following permission prompt should be shown:

Exit the non-secure context deprecation trial

For websites which registered Private Network Access for non-secure contexts deprecation trial, this is the time for you to migrate your website with our new permission prompt and exit the trial now.

After updating your code, delete the trial token in your HTML, JavaScript, or HTTP headers. If you don't remember where you put the trial token, refer to the Register for deprecation trial section in the previous blog post.

You might also want to delete the token in the trial's page.

What's next?

Solution for requests from non-API fetch() is still under exploration.

Several solutions have been tested, for example, using service workers or making target address space as a new Content-Security-Policy. However the final shape for requests from non-API fetch() is still under investigation.

Requests from sub frames might be supported with permission policy in the future.

In the future, we might want to support permission policies to relax the ability for sub frames.

Feedback for private network use cases

If you host a website on a private network that needs requests from public networks, the Chrome team wants your feedback! File an issue at the Chromium Issue Tracker (component: Blink>SecurityFeature>CORS>PrivateNetworkAccess) or on the GitHub repository.