Origin trial for HTTP header support in Storage Access

Natalia Markoborodova
Natalia Markoborodova

Chrome is starting an origin trial for adding HTTP headers to the Storage Access API (SAA) in version 130: Storage Access Headers. The new Sec-Fetch-Storage-Access request header and Activate-Storage-Access response header aim to support non-iframe resources, and improve performance and user experience for websites that rely on embedded content, such as social media widgets, calendars, and interactive tools.

JavaScript flow (and its limitations)

Previously, SAA required a JavaScript API call to document.requestStorageAccess() on every reload, even if the user has already granted permission. While effective, this method introduces limitations:

  • Multiple network round trips: The process often involved several network requests and page reloads before the embedded content could fully function.
  • Iframe dependency: JavaScript execution mandated the use of iframes or subresources within iframes, limiting flexibility for developers.

For example, a calendar widget from calendar.example embedded on website.example using only JavaScript would look like this:

  1. Load a placeholder: website.example requests the widget. As the calendar.example widget embedded on website.example doesn't have access to its unpartitioned cookies, a placeholder widget is rendered instead.
  2. Request permission: The placeholder loads, then calls document.requestStorageAccess() to request storage-access permission.
  3. The user chooses to grant permission.
  4. Reload the widget: The widget refreshes, this time with cookie access, and finally loads the personalized content.
  5. Each time the user visits a site embedding the calendar.example widget again, the flow looks exactly the same as in steps 1, 2, and 4; the only simplification is that the user does not need to re-grant access.

This flow is inefficient: if the user has already granted storage permission, the initial iframe load, the document.requestStorageAccess() call, and the subsequent reload become unnecessary, and create latency.

The new flow with HTTP Headers

The new Storage Access Headers enable more efficient loading of embedded content, including non-iframe resources.

With Storage Access Headers, the browser will automatically fetch resources with the Sec-Fetch-Storage-Access: inactive request header set if the user has already granted permission. No developer action is required to set the request header. The server can respond with the Activate-Storage-Access: retry; allowed-origin=<origin> header, and the browser will retry the request with the necessary credentials.

Request Header

Sec-Fetch-Storage-Access: <access-status>

When a user visits a page that embeds cross-site content, the browser will automatically include the Sec-Fetch-Storage-Access header in cross-site requests that might require credentials (like cookies). This header indicates the embed's cookie access permission status. Here's how to interpret its values:

  • none: the embed doesn't have the storage-access permission, and therefore doesn't have access to unpartitioned cookies.
  • inactive: the embed has the storage-access permission, but has not opted into using it. The embed does not have unpartitioned cookie access.
  • active: the embed has unpartitioned cookie access. This value will be included on any cross-origin requests that have access to unpartitioned cookies.

Response Headers

Activate-Storage-Access: <retry-or-reload>

The Activate-Storage-Access header instructs the browser to either retry the request with cookies or load the resource directly with SAA activated. The header can have the following values:

  • load: instructs the browser to grant the embedder access to unpartitioned cookies for the requested resource.
  • retry: the server responds that the browser should activate the storage-access permission, then retry the request.
Activate-Storage-Access: retry; allowed-origin="https://site.example"
Activate-Storage-Access: retry; allowed-origin=*
Activate-Storage-Access: load

Support for non-iframe resources

The Storage Access Headers update enables SAA for non-iframe embedded content, like images hosted on a different domain. Previously, no web platform API allowed loading such resources with credentials in browsers if third-party cookies are unavailable. For example, your embedding-site.example can request an image:

   <img src="https://server.example/image"/>

And the server can respond with content or an error, depending on whether a cookie is available:

app.get('/image', (req, res) => {
  const headers = req.headers;
  const cookieHeader = headers.cookie;
  // Check if the embed has the necessary cookie access
  if (!cookieHeader || !cookieHeader.includes('foo')) {
  // If the cookie is not present, check if the browser supports Storage Access headers
    if (
      'sec-fetch-storage-access' in headers &&
      headers['sec-fetch-storage-access'] == 'inactive'
    ) {
    // If the browser supports Storage Access API, retry the request with storage access enabled
      res.setHeader('Activate-Storage-Access', 'retry; allowed-origin="https://embedding-site.example"');
    }
    res.status(401).send('No cookie!');
   } else {
    // If the cookie is available, check if the user is authorized to access the image
    if (!check_authorization(cookieHeader)) {
      return res.status(401).send('Unauthorized!');
    }
    // If the user is authorized, respond with the image file
    res.sendFile("path/to/image.jpeg");
  }
});

If the cookie is not available, the server checks the value of the Sec-Fetch-Storage-Access request header. If this value is set to inactive, the server responds with the Activate-Storage-Access: retry header, indicating that the request should be retried with storage access. If there is no cookie and the Sec-Fetch-Storage-Access header does not have the value inactive, the image won't load.

HTTP Header flow

With HTTP headers, the browser can recognize when the user has already granted storage-access permission to the widget, and load the iframe with access to unpartitioned cookies during subsequent visits.

With Storage Access Headers, the subsequent pages visits will trigger the following flow:

  1. The user visits website.example that has the calendar.example embedded again. This fetch doesn't yet have access to the cookie, as before. However, the user has previously granted storage-access permission, and the fetch includes a Sec-Fetch-Storage-Access: inactive header, to indicate that unpartitioned cookie access is available but not in use.
  2. The calendar.example server responds with a Activate-Storage-Access: retry; allowed-origin=<origin> header (in this case, <origin> would be https://website.example), to indicate that the resource fetch requires the use of unpartitioned cookies with the storage-access permission.
  3. The browser retries the request, this time including unpartitioned cookies (activating the storage-access permission for this fetch).
  4. The calendar.example server responds with the personalized iframe content. The response includes a Activate-Storage-Access: load header, to indicate that the browser should load the content with the storage-access permission activated (in other words, load with unpartitioned cookie access, as if document.requestStorageAccess() had been called).
  5. The user agent loads the iframe content with unpartitioned cookie access using the storage-access permission. After this step, the widget can work as expected.
A flowchart illustrating the Storage Access Header flow
Storage Access Header flow diagram.

Update your solution

With the Storage Access Headers feature, you may want to update your code in two cases:

  1. You use SAA and want to achieve better performance with header logic.
  2. You have a validation or logic that depends on whether the Origin header is included in the request on your server.

Implement SAA headers logic

In order to use Storage Access Headers in your solution, you need to update your solution. Suppose you're the calendar.example owner. For website.example to be able to load a personalized calendar.example widget, the widget code must have storage access.

Client side

The Storage Access Headers feature doesn't require any code update on the client side for the existing solutions. Read the documentation to learn how to implement SAA.

Server side

On the server side, you can use the new headers:

app.get('/cookie-access-endpoint', (req, res) => {
  const storageAccessHeader = req.headers['sec-fetch-storage-access'];

  if (storageAccessHeader === 'inactive') {
    // User needs to grant permission, trigger a prompt
    if (!validate_origin(req.headers.origin)) {
      res.status(401).send(`${req.headers.origin} is not allowed to send` +
          ' credentialed requests to this server.');
      return;
    }
    res.set('Activate-Storage-Access', `retry; allowed-origin=${req.headers.origin}`);
    res.status(401).send('This resource requires storage access. Please grant permission.');
  } else if (storageAccessHeader === 'active') {
    // User has granted permission, proceed with access
    res.set('Activate-Storage-Access', 'load');
    // Include the actual iframe content here
    res.send('This is the content that requires cookie access.');
  } else {
    // Handle other cases (e.g., 'Sec-Fetch-Storage-Access': 'none')
  }
});

Check out the demo to see how this solution works in practice.

Update your Origin header logic

With Storage Access Headers, Chrome sends the Origin header in more requests than before. This could affect your server-side logic if it relies on the Origin header only being present for specific types of requests (like those defined by CORS).

To avoid potential issues, you need to review your server-side code:

  • Check for any validation or logic that depends on the presence of the Origin header.
  • Update your code to handle the Origin header being present in more cases.

Key advantages

Storage Access Headers is a recommended, more performant way to use the SAA. Overall, this change brings several improvements:

  • Non-iframe embeds support: Enables SAA for a wider range of resources.
  • Reduced network usage: Fewer requests and smaller payloads.
  • Lower CPU usage: Less JavaScript processing.
  • Improved UX: Eliminates disruptive intermediate loads.

Participate in the origin trial

Origin trials allow you to try new features and give feedback on their usability, practicality, and effectiveness. For more information, check out the Get started with origin trials.

You can try the Storage Access Headers feature by registering for the origin trials starting from Chrome 130. To participate in the origin trial:

  1. Go to the Storage Access Headers origin trial registration page.
  2. Follow the instructions on origin trial participation.

Test locally

You can test the Storage Access Headers feature locally to ensure your website is prepared for this change.

Follow these steps to configure your Chrome instance:

  1. Enable the chrome flag on chrome://flags/#storage-access-headers.
  2. Restart Chrome for the changes to take effect.

Engage and share feedback

If you have feedback or encounter any problems, you can file an issue. You can also learn more about the Storage Access Headers on the GitHub explainer.