Storage Access API
Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.
The Storage Access API provides a way for cross-site content loaded in a third-party context (i.e., embedded in an <iframe>) to gain access to third-party cookies and unpartitioned state that it would typically only have access to in a first-party context (i.e., when loaded directly in a browser tab).
The Storage Access API is relevant to user agents that, by default, block access to third-party cookies and unpartitioned state to improve privacy (for example, to prevent tracking). There are legitimate uses for third-party cookies and unpartitioned state that we still want to enable, even with these default restrictions in place. Examples include single sign-on (SSO) with federated identity providers (IdPs), or persisting user details such as location data or viewing preferences across different sites.
The API provides methods that allow embedded resources to check whether they currently have access to third-party cookies and, if not, to request access from the user agent.
Concepts and usage
Browsers implement several storage access features and policies restricting access to third-party cookies and unpartitioned state. These range from giving embedded resources under each top-level origin a unique cookie storage space (partitioned cookies) to outright blocking of cookie access when resources are loaded in a third-party context.
The semantics around third-party cookie and unpartitioned state blocking features and policies differ from browser to browser, but the core functionality is similar. Cross-site resources embedded in a third-party context are not given access to the same state that they would have access to when loaded in a first-party context. This is done with good intent — browser vendors want to take steps to better protect their user's privacy and security. Examples include leaving them less open to having their activity tracked across different sites, and less vulnerable to exploits such as cross-site request forgery (CSRF).
However, there are legitimate uses for embedded cross-site content accessing third-party cookies and unpartitioned state, which the above features and policies are known to break. Let's say you've got a series of different sites that provide access to different products — heads-example.com, shoulders-example.com, knees-example.com, and toes-example.com.
Alternatively, you might separate your content or services into different country domains for localization purposes — example.com, example.ua, example.br, etc. — or in some other way.
You might have accompanying utility sites with components embedded in all the other sites, for example, to provide SSO (sso-example.com) or general personalization services (services-example.com). These utility sites will want to share their state with the sites they are embedded in via cookies. They cannot share first-party cookies because they are on different domains, and third-party cookies will no longer work in browsers that block them.
In such situations, site owners often encourage users to add their site as an exception or to disable third-party cookie-blocking policies entirely. Users who wish to continue interacting with their content must significantly relax their blocking policy for resources loaded from all embedded origins and possibly across all websites.
The Storage Access API is intended to solve this problem; embedded cross-site content can request unrestricted access to third-party cookies and unpartitioned state on a frame-by-frame basis via the Document.requestStorageAccess() method.
It can also check whether it already has access via the Document.hasStorageAccess() method.
Note: The storage access headers are an HTTP extension to the API that enables a more efficient storage API workflow, and can also be used to activate a previously granted storage access permission for passive resources, such as images.
Unpartitioned versus partitioned cookies
The Storage Access API is only needed to provide access to unpartitioned third-party cookies! Unpartitioned cookies are those where all cookies set on the same site are stored in the same cookie jar — the traditional way since the early web. Because there is a risk of exposing data intended for one site to other sites, browsers commonly block sending unpartitioned third-party cookies in requests, and don't allow access to them in embedded contexts.
This is in contrast to partitioned cookies, where embedded resources under each top-level site are given a unique cookie storage space, isolated from those of other sites. Since there is no privacy risk, because it is not possible to track users across sites via partitioned cookies, browsers send partitioned cookies in requests and make them available to embedded resources. Note however that, because the cookies aren't shared between sites, they are also not automatically synchronized across sites. Browsers have various mechanisms to partition third-party cookie access, for example Firefox Total Cookie Protection and Cookies Having Independent Partitioned State (CHIPS).
When we talk about third-party cookies in the context of the Storage Access API, we implicitly mean unpartitioned third-party cookies.
How it works
Third party content embedded in an <iframe> that needs to access cookie or other unpartitioned state can request access using the Storage Access API as follows:
-
Document.hasStorageAccess()can be called to check if the embedded content already has access to unpartitioned cookies. -
If not,
Document.requestStorageAccess()can be called with transient activation to request thestorage-accesspermission.Depending on the browser, the user will be asked whether to grant permission to the requesting embed in slightly different ways.
- Safari shows prompts for all embedded content that has not previously received storage access.
- Firefox only prompts users after an origin has requested storage access on more than a threshold number of sites.
- Chrome shows prompts for all embedded content that has not previously received storage access. It will however automatically grant access and skip prompts if the embedded content and embedding site are part of the same related website set.
-
Permission is granted or denied based on whether the content meets all the security requirements — see Security considerations for general requirements, and Browser-specific variations for some browser-specific security requirements. The
Promise-based nature ofrequestStorageAccess()allows you to run code to handle success and failure cases.Once permission is granted, a permission key is stored in the browser with the structure
<top-level site, embedded site>. For example, if the embedding site isembedder.com, and the embed islocator.example.com, the key would be<embedder.com, example.com>.This means that permission is granted for unpartitioned cookie access to any page on the
example.comsite or any of its subdomains embedded in any page on theembedder.comsite. For example,docs.example.com,profile.example.com, can now callrequestStorageAccess()and the promise would fulfill automatically.Note: Older spec versions used the more specific permission key structure
<top-level site, embedded origin>, which meant that same-site, cross-origin embeds didn't match the permission key and had to go through the whole process separately. -
Permission must be explicitly activated for each context.
When an embed is granted permission, that permission is also activated for the current context. However, other contexts, such as new browser tabs or content in other
<iframe>elements in the page, have their third-party cookie access blocked by default. That means that even if permission is granted, the page will need to load and callrequestStorageAccess()to activate the permission. If permission has already been granted then a call torequestStorageAccess()will not require transient activation and the promise will fulfill automatically.The only exception to the "blocked by default" behavior is if an embed performs a same-origin navigation to reload itself after after being granted permission or activating a permission. In such cases, the storage access is carried over from the previous navigation. This allows the embedded resource to reload itself and gain access to its cookies.
Note: In older spec versions, the access was per-page (Safari is the only browser still using this model). When one embed received third-party cookie access via
requestStorageAccess(), all other same-site embeds would automatically receive access. This was not desirable behavior from a security standpoint — for example, ifshop.example.comembeddedlocator.users.comto allow users to use their location info while shopping, andlocator.users.comcalledrequestStorageAccess(),shop.example.comand any other sites it embeds would be able to access its cookies, but also access cookies fromprivate.users.com, which is not intended to be embedded. Read more about the motivations behind this change. -
After an embed has activated the storage-access permission it should reload itself. The browser will re-request the resource with third-party cookies included, and make them available to the embedded resource once it has loaded.
Storage access headers
The API requires that a resource must must call requestStorageAccess() for each new context to opt-in to activating the storage-access permission, which must already have been granted.
This in turn means that the embedded resource must first be requested without cookies and loaded so it can call the method.
The storage access headers enable a workflow where the server can request that the permission is activated for the context, avoiding an unnecessary additional load of the embedded resource if permission has already been granted. The resource must still be loaded in order to request permission the first time.
There are two headers:
- The browser adds the
Sec-Fetch-Storage-Accessheader to requests to indicate the storage access state of the current fetch context, such as whether permission has been activated, granted, or not granted. - Depending on the storage access state of the request, the server can respond with an
Activate-Storage-Accessheader to request that the browser activate the permission for the context and retry the request with cookies (avoiding it having to load the resource so it can callrequestStorageAccess()to achieve the same thing), or activate the permission and load the returned resource.
The storage access headers can also be used to activate permission for passive resources, such as images, provided the context has already been granted permission. This might be used, for example, to serve different images for different users, demographics, or locales.
The workflows are shown in the Storage access header sequences section.
Request/response flow
JavaScript sequences
Consider the example of a library loaded in an <iframe> that needs to be shared across a number of sites and relies on credentials stored in unpartitioned cookies.
First let's look at the case where permission has not been granted:
-
The browser requests the resource without including third-party cookies.
-
The server responds with a "fallback" version of content that does not rely on credentials, and that when loaded doesn't have access to its cookies.
- Once loaded, the resource calls
requestStorageAccess()with transient activation to request and activate thestorage-accesspermission. - If permission is granted, the resource will then reload itself.
- Once loaded, the resource calls
-
The browser requests the resource again, this time including third-party cookies.
-
The server response includes a "credentialed" version of the resource.
The browser loads the resource, which has access to its own cookies because it has an activated storage-access permission.

Now consider the case where permission has been granted but not activated. This would happen if you were to open the same URL in a new browser tab, or attempt to embed the same resource from another page in the same site.
The workflow is almost exactly the same because the resource still needs to be loaded the first time without cookies, and it then needs to call requestStorageAccess() to activate the permission for the context.
In this case, however, it doesn't need transient activation and can execute on load.

Storage access header sequences
The storage access headers enable an improved workflow that allows the server to request that the browser activate a permission that has been granted and retry the request with cookies included.
This avoids the requirement to load the resource to call requestStorageAccess() when the user has already granted permission.
Note:
These headers do not provide a mechanism to grant the storage access permission in the first place.
Permission must always be requested by the embedded resource calling requestStorageAccess() with transient activation.
The Sec-Fetch-Storage-Access header is added to requests to indicate the storage access state of the current fetch context, such as whether permission has been activated, granted, or not granted.
Depending on the storage access state of the request, the server can respond with an Activate-Storage-Access header to request that the browser activate the permission for the context and retry the request with cookies.
First let's look at the case of attempting to load an embedded resource for a new context that already has permission granted:
- The browser sends a request with
Sec-Fetch-Storage-Access: inactiveto indicate that the permission is granted but inactive for the context.- The request will also include the
Originheader to help the server decide if it wants to activate the permission.
- The request will also include the
- The server can then respond with
Activate-Storage-Access: retryto indicate that the browser should activate the permission, and retry the request with cookies.- The response should also include the
Vary: Sec-Fetch-Storage-Accessheader, as it depends on the value ofSec-Fetch-Storage-Access. - Note that the response doesn't include content.
- The response should also include the
- If the browser retries the request, it adds
Sec-Fetch-Storage-Access: activeto the request along with the cookies. - The server then responds with
Activate-Storage-Access: load, which tells the browser to load the new version of the library with access to third-party cookies.

The last state to consider is when loading an embedded resource for which permission has not been granted:
Note: Because we can't use the headers to grant permission, we need to load the resource without cookies so that it can request the permission. This is the same sequence as if the headers were not applied.
-
The browser sends a request with
Sec-Fetch-Storage-Access: noneto indicate that the permission has not been granted. -
The server then responds with the resource, which when loaded requests permission for secure access with transient activation. The
Activate-Storage-Accessheader isn't included in the response, but the server should addVary: Sec-Fetch-Storage-Access.After the user has granted (and thereby activated) the permission, the embed reloads itself.
-
The browser adds
Sec-Fetch-Storage-Access: activeto the request to indicate the context has an activatedstorage-accesspermission, and includes the third-party cookies. -
The server responds with
Activate-Storage-Access: load, which tells the browser to load the new version of the library with access to third-party cookies.

Security considerations
Several different security measures could cause a Document.requestStorageAccess() call to fail.
Check the below list if you are having trouble getting a request to work:
-
The permission request must be associated with a user gesture (transient activation) such as a tap or click. This prevents embedded content on the page from spamming the browser or user with excessive access requests. Note that this isn't required if:
- Permission to use the API has already been granted to another context with the same
<top-level site, embedded site>key. - The caller is a top-level document or same-site to the top-level document.
In such cases,
requestStorageAccess()probably doesn't need to be called at all.
- Permission to use the API has already been granted to another context with the same
-
The document and top-level document must not have a
nullorigin. -
Origins that have never been interacted with as a first party do not have a notion of first-party storage. From the user's perspective, they only have a third-party relationship with that origin. Access requests are automatically denied if the browser detects that the user hasn't interacted with the embedded content in a first-party context recently (in Firefox, "recently" means within 30 days).
-
The document's window must be a secure context.
-
Sandboxed
<iframe>s cannot be granted storage access by default for security reasons. To handle this, the API provides theallow-storage-access-by-user-activationsandbox token. The<iframe>needs to include this to enable storage access requests, along withallow-scriptsandallow-same-originto allow it to execute a script to call the API and execute it in an origin that can have cookies/state:html<iframe sandbox="allow-storage-access-by-user-activation allow-scripts allow-same-origin"> … </iframe> -
Usage of this feature may be blocked by a
storage-accessPermissions Policy set on your server.
Note: The document may also be required to pass additional browser-specific checks. Examples: allowlists, blocklists, on-device classification, user settings, anti-clickjacking heuristics, or prompting the user for explicit permission.
Browser-specific variations
Although the API surface is the same, websites using the Storage Access API should expect differences in the level and extent of third-party cookie access they receive between different browsers, due to differences in their storage access policies.
Chrome
- Cookies must have
SameSite=Noneexplicitly set on them, because the default value for Chrome isSameSite=Lax(SameSite=Noneis the default in Firefox and Safari). - Cookies must have the
Secureattribute set on them. - The storage access grants are phased out after 30 days of browser usage passed without user interaction. Interaction with the embedded content extends this limit by another 30 days. This doesn't occur when
Document.requestStorageAccessFor()is called because the user is already on the page.
Firefox
- If the embedded origin
tracker.examplehas already obtained third-party cookie access on the top-level originfoo.example, and the user visits a page fromfoo.exampleembedding a page fromtracker.exampleagain in less than 30 days, the embedded origin will have third-party cookie access immediately when loading. - The storage access grants are phased out after 30 calendar days have passed.
Documentation for Firefox's new storage access policy for blocking tracking cookies includes a detailed description of the scope of storage access grants.
Safari
- The storage access grants are phased out after 30 days of browser usage passed without user interaction. Successful use of the Storage Access API resets this counter.
Examples
- See Using the Storage Access API for an implementation guide with code examples.
API methods
Document.hasStorageAccess()-
Returns a
Promisethat resolves with a boolean value indicating whether the document has access to third-party cookies. -
New name for
Document.hasStorageAccess(). Document.requestStorageAccess()-
Allows content loaded in a third-party context (i.e., embedded in an
<iframe>) to request access to third-party cookies and unpartitioned state; returns aPromisethat resolves if the access was granted, and rejects if access was denied. Document.requestStorageAccessFor()Experimental-
A proposed extension to the Storage Access API that allows top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set. Returns a
Promisethat resolves if the access was granted, and rejects if access was denied.
Note: User interaction propagates to the promise returned by these methods, allowing the callers to take actions requiring user interaction without requiring a second click. For example, a caller could open a pop-up window from the resolved promise without triggering Firefox's pop-up blocker.
Additions to other APIs
Permissions.query(), the"storage-access"feature name-
In supporting browsers, this can query whether third-party cookie access has been granted in general, that is, to another same-site embed. If so, you can call
requestStorageAccess()without user interaction, and the promise will resolve automatically. Permissions.query(), the"top-level-storage-access"feature name Experimental-
A separate feature name used to query whether permission to access third-party cookies has already been granted via
requestStorageAccessFor(). If so, you don't need to callrequestStorageAccessFor()again.
Additions to HTTP
Permissions-Policy
Permissions-Policy: storage-access-
The
storage-accessPermissions-Policydirective controls whether a document loaded in a third-party context (i.e., embedded in an<iframe>) is allowed to use the storage access API to request access to unpartitioned cookies.
Storage access headers
Sec-Fetch-Storage-Access-
Indicates the "storage access status" for the current request context, which will be one of
none,inactive, oractive. Activate-Storage-Access-
Used in response to
Sec-Fetch-Storage-Accessto indicate that the browser can activate an existing permission for secure access and retry the request with cookies, or load a resource with cookie access if it already has an activated permission.
Specifications
| Specification |
|---|
| The Storage Access API> |
| Extending Storage Access API (SAA) to non-cookie storage> |
Browser compatibility
>api.Document.hasStorageAccess
Loading…
api.Document.hasUnpartitionedCookieAccess
Loading…
api.Document.requestStorageAccess
Loading…
api.Document.requestStorageAccessFor
Loading…
api.Permissions.permission_storage-access
Loading…
http.headers.Activate-Storage-Access
Loading…
http.headers.Sec-Fetch-Storage-Access
Loading…
See also
- Using the Storage Access API
- Introducing Storage Access API (WebKit blog)