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:
- Load a placeholder:
website.example
requests the widget. As thecalendar.example
widget embedded onwebsite.example
doesn't have access to its unpartitioned cookies, a placeholder widget is rendered instead. - Request permission: The placeholder loads, then calls
document.requestStorageAccess()
to requeststorage-access
permission. - The user chooses to grant permission.
- Reload the widget: The widget refreshes, this time with cookie access, and finally loads the personalized content.
- 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 thestorage-access
permission, and therefore doesn't have access to unpartitioned cookies.inactive
: the embed has thestorage-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:
- The user visits
website.example
that has thecalendar.example
embedded again. This fetch doesn't yet have access to the cookie, as before. However, the user has previously grantedstorage-access
permission, and the fetch includes aSec-Fetch-Storage-Access: inactive
header, to indicate that unpartitioned cookie access is available but not in use. - The
calendar.example
server responds with aActivate-Storage-Access: retry; allowed-origin="<origin>"
header (in this case,<origin>
would behttps://website.example
), to indicate that the resource fetch requires the use of unpartitioned cookies with the storage-access permission. - The browser retries the request, this time including unpartitioned cookies (activating the
storage-access
permission for this fetch). - The
calendar.example
server responds with the personalized iframe content. The response includes aActivate-Storage-Access: load
header, to indicate that the browser should load the content with thestorage-access
permission activated (in other words, load with unpartitioned cookie access, as ifdocument.requestStorageAccess()
had been called). - 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.
Update your solution
With the Storage Access Headers feature, you may want to update your code in two cases:
- You use SAA and want to achieve better performance with header logic.
- 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:
- Go to the Storage Access Headers origin trial registration page.
- 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:
- Enable the chrome flag on
chrome://flags/#storage-access-headers
. - 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.