Storage Access API

Third-party cookie blocking by browsers, user settings, and storage partitioning, pose a challenge for sites and services that rely on cookies and other storage in embedded contexts, for user journeys such as authentication. The Storage Access API (SAA) allows these use cases to continue to work, while limiting cross-site tracking as much as possible.

Implementation status

Browser Support

  • Chrome: 119.
  • Edge: 85.
  • Firefox: 65.
  • Safari: 11.1.

Source

The Storage Access API is available in all major browsers, but there are slight implementation differences between browsers. These differences have been highlighted in the relevant sections in this post.

Work is continuing to resolve all remaining blocking issues, before standardizing the API.

What is the Storage Access API?

The Storage Access API is a JavaScript API that allows iframes to request storage access permissions when access would otherwise be denied by browser settings. Embeds with use cases that depend on loading cross-site resources can use the API to request access permission from the user, on an as-needed basis.

If the storage request is granted, then the iframe will have access to its unpartitioned cookies and storage, which are also available when users visit it as a top-level site.

The Storage Access API allows specific unpartitioned cookie and storage access to be provided with minimal burden to the end user, while still preventing generic unpartitioned cookie and storage access as is often used for user tracking.

Use cases

Some third-party embeds require access to unpartitioned cookies or storage to provide a better experience to the user—something that won't be available when third-party cookies are restricted and storage partitioning is enabled.

Use cases include:

  • Embedded commenting widgets which require login session details.
  • Social media "Like" buttons which require login session details.
  • Embedded documents which require login session details.
  • A premium experience provided to a video embed (for example, to not show ads for logged in users, or to know the user's preferences for closed captions or restrict certain video types).
  • Embedded payment systems.

Many of these use cases involve persisting login access in embedded iframes.

When to use the Storage Access API over other APIs

The Storage Access API is one of the alternatives to using unpartitioned cookies and storage, so it is important to understand when to use this API compared to the others. It's meant for use cases where both the following are true:

  • The user will interact with the embedded content—that is, it is not a passive iframe or a hidden iframe.
  • The user has visited the embedded origin in a top-level context—that is, when that origin is not embedded in another site.

There are alternative APIs for a variety of use cases:

  • Cookies Having Independent Partitioned State (CHIPS) allows developers to opt-in a cookie to "partitioned" storage, with a separate cookie jar per top-level site. For example, a third-party web-chat widget may rely on setting a cookie to save session information. The session information is saved per-site, so the cookie set by the widget doesn't need to be accessed on other websites where it is also embedded. The Storage Access API is useful when an embedded third-party widget is dependent on sharing the same information across different origins (for example for logged-in session details or preferences).
  • Storage Partitioning is a way for cross-site iframes to use existing JavaScript storage mechanisms while dividing the underlying storage per-site. This prevents embedded storage in one website from being accessed by the same embed on other websites.
  • Related Websites Sets (RWS) is a way for an organization to declare relationships among sites, so that browsers allow limited unpartitioned cookie and storage access for specific purposes. Sites still need to request access with the Storage Access API, but for sites within the set, access can be granted without user prompts.
  • Federated Credential Management (FedCM) is a privacy-preserving approach to federated identity services. The Storage Access API deals with accessing unpartitioned cookies and storage post-login. For some use cases FedCM provides an alternative solution to the Storage Access API, and may be preferable as it features a more login-oriented browser prompt. However, adopting FedCM usually requires additional changes to your code, for example to support its HTTP endpoints.
  • Anti-fraud, ad-related, and measurement APIs also exist, and the Storage Access API is not intended to address those concerns.

Use the Storage Access API

The Storage Access API has two promised-based methods:

It also integrates with the Permissions API. This lets you check the status of the storage-access permission in a third-party context, which indicates whether a call to document.requestStorageAccess() would be automatically granted:

Use the hasStorageAccess() method

When a site first loads, it can use the hasStorageAccess() method to check whether access to third-party cookies has already been granted.

// Set a hasAccess boolean variable which defaults to false.
let hasAccess = false;

async function handleCookieAccessInit() {
  if (!document.hasStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    hasAccess = true;
  } else {
    // Check whether access has been granted using the Storage Access API.
    // Note on page load this will always be false initially so we could be
    // skipped in this example, but including for completeness for when this
    // is not so obvious.
    hasAccess = await document.hasStorageAccess();
    if (!hasAccess) {
      // Handle the lack of access (covered later)
    }
  }
  if (hasAccess) {
    // Use the cookies.
  }
}
handleCookieAccessInit();

Storage access is only granted to an iframe document after it calls requestStorageAccess(), so hasStorageAccess() will always return false initially—except when another same-origin document in the same iframe had already been granted access. The grant is preserved across same-origin navigations inside the iframe specifically to allow reloads after granting access for pages that require cookies to be present in the initial request for the HTML document.

Use requestStorageAccess()

If the iframe does not have access it may need to request access using the requestStorageAccess() method:

if (!hasAccess) {
  try {
    await document.requestStorageAccess();
  } catch (err) {
    // Access was not granted and it may be gated behind an interaction
    return;
  }
}

The first time this is requested, the user may need to approve this access with a browser prompt, after which the promise will resolve, or will reject resulting in an exception if await is used.

To prevent abuse, this browser prompt will only be shown after a user interaction. That's why requestStorageAccess() initially needs to be called from a user-activated event handler, rather than immediately as the iframe loads:

async function doClick() {

  // Only do this extra check if access hasn't already been given
  // based on the hasAccess variable.
  if (!hasAccess) {
    try {
      await document.requestStorageAccess();
      hasAccess = true; // Can assume this was true if requestStorageAccess() did not reject.
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  if (hasAccess) {
    // Use the cookies
  }
}

document.querySelector('#my-button').addEventListener('click', doClick);

If you need to use local storage instead of cookies, you could do the following:

let handle = null;

async function doClick() {
  if (!handle) {
    try {
      handle = await document.requestStorageAccess({localStorage: true});
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  // Use handle to access unpartitioned local storage.
  handle.localStorage.setItem('foo', 'bar');
}

document.querySelector('#my-button').addEventListener('click', doClick);

Permission prompts

When the user clicks the button for the first time, the browser prompt will automatically appear in most cases, typically in the address bar. The following screenshot shows an example of Chrome's prompt, but other browsers have a similar UI:

Chrome Storage Access API permission prompt
Chrome's Storage Access API permission prompt

The prompt may be skipped by the browser and permission automatically provided in certain circumstances:

  • If the page and iframe have been used in the last 30 days after accepting the prompt.
  • If the embedded iframe is part of a Related Website Set.
  • If FedCM is used as a trust signal for storage access.
  • In Firefox, the prompt is also skipped for known websites (those you have interacted with at the top level) for the first five attempts.

Alternatively, the method may be automatically rejected without showing the prompt in certain circumstances:

  • If the user has not previously visited and interacted with the site that owns the iframe as a top-level document, not in an iframe. This means the Storage Access API is only useful for embedded sites that users have previously visited in a first-party context.
  • If the requestStorageAccess() method is called outside of a user interaction event without prior approval of the prompt after an interaction.

While the user will be prompted on the initial use, subsequent visits can resolve requestStorageAccess() without a prompt and without requiring user interaction in Chrome and Firefox. Note that Safari always requires a user interaction.

As cookie and storage access may be granted without a prompt, or user interaction, it is often possible to get unpartitioned cookie or storage access before a user interaction on browsers that support this (Chrome and Firefox) by calling requestStorageAccess() on page load. This may allow you to access unpartitioned cookies and storage immediately and provide a fuller experience, even before the user interacts with the iframe. This can be a better user experience for some situations than waiting for user interaction.

FedCM as a trust signal for SAA

FedCM (Federated Credential Management) is a privacy-preserving approach to federated identity services (such as "Sign in with...") that doesn't rely on third-party cookies or navigational redirects.

When a user logs in to a Relying Party (RP) that has some embedded content from a third-party identity provider (IdP) with FedCM, the embedded IdP content can automatically get storage access to its own top-level unpartitioned cookies. To enable automatic storage access with FedCM, these conditions must be met:

  • The FedCM authentication (the user sign-in state) must be active.
  • The RP has opted in by setting the identity-credentials-get permission, for example:
<iframe src="https://idp.example" allow="identity-credentials-get"></iframe>

For example, an idp.example iframe is embedded in rp.example. When the user logs in with FedCM, the idp.example iframe can request storage access for its own top-level cookies.

The rp.example makes a FedCM call to log the user in with the identity provider idp.example:

// The user will be asked to grant FedCM permission.
const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://idp.example/fedcm.json',
      clientId: '123',
    }],
  },
});

After the user logs in, IdP can call requestStorageAccess() from within the idp.example iframe, as long as the RP has explicitly allowed this with Permissions Policy. The embed will be automatically granted storage access to its own top-level cookie, without user activation or the need for another permission prompt:

// Make this call within the embedded IdP iframe:

// No user gesture is needed, and the storage access will be auto-granted.
await document.requestStorageAccess();

// This returns `true`.
const hasAccess = await document.hasStorageAccess();

The permission will be auto-granted only as long as the user is signed in with FedCM. Once the authentication is inactive, standard SAA requirements apply to grant storage access.

Use the storage-access permission query

To check whether access can be granted without a user interaction, you can check the status of the storage-access permission and only make the requestStoreAccess() call early if no user action is required, rather than call it and have it fail when an interaction is required.

This also lets you potentially handle the need for a prompt upfront by displaying different content—for example, a login button.

The following code adds the storage-access permission check to the earlier example:

// Set a hasAccess boolean variable which defaults to false except for
// browsers which don't support the API - where we assume
// such browsers also don't block third-party cookies.
let hasAccess = false;

async function hasCookieAccess() {
  // Check if Storage Access API is supported
  if (!document.requestStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    return true;
  }

  // Check if access has already been granted
  if (await document.hasStorageAccess()) {
    return true;
  }

  // Check the storage-access permission
  // Wrap this in a try/catch for browsers that support the
  // Storage Access API but not this permission check
  // (e.g. Safari and earlier versions of Firefox).
  let permission;
  try {
    permission = await navigator.permissions.query(
      {name: 'storage-access'}
    );
  } catch (error) {
    // storage-access permission not supported. Assume no cookie access.
    return false;
  }

    if (permission) {
    if (permission.state === 'granted') {
      // Permission has previously been granted so can just call
      // requestStorageAccess() without a user interaction and
      // it will resolve automatically.
      try {
        await document.requestStorageAccess();
        return true;
      } catch (error) {
        // This shouldn't really fail if access is granted, but return false
        // if it does.
        return false;
      }
    } else if (permission.state === 'prompt') {
      // Need to call requestStorageAccess() after a user interaction
      // (potentially with a prompt). Can't do anything further here,
      // so handle this in the click handler.
      return false;
          } else if (permission.state === 'denied') {
            // Not used: see https://github.com/privacycg/storage-access/issues/149
      return false;
          }
    }

  // By default return false, though should really be caught by earlier tests.
  return false;
}

async function handleCookieAccessInit() {
  hasAccess = await hasCookieAccess();

  if (hasAccess) {
    // Use the cookies.
  }
}

handleCookieAccessInit();

Sandboxed iframes

When using the Storage Access API in sandboxed iframes, the following sandbox permissions are required:

  • allow-storage-access-by-user-activation is required to allow access to the Storage Access API.
  • allow-scripts is required to allow use of JavaScript to call the API.
  • allow-same-origin is required to allow access to same-origin cookies and other storage.

For example:

<iframe sandbox="allow-storage-access-by-user-activation
                 allow-scripts
                 allow-same-origin"
        src="..."></iframe>

To be accessed with the Storage Access API in Chrome, cross-site cookies must be set with the following two attributes:

  • SameSite=None - which is required to mark the cookie as cross-site
  • Secure - which ensures only cookies set by HTTPS sites can be accessed.

In Firefox and Safari, cookies are defaulted to SameSite=None and they don't restrict SAA to Secure cookies so these attributes are not required. It is recommended to be explicit about the SameSite attribute and to always use Secure cookies.

Top-level page access

The Storage Access API is intended for enabling access to third-party cookies within embedded iframes.

There are also other use cases when the top-level page requires access to third-party cookies. For example, images or scripts which are restricted by cookies, which site owners may want to include directly in the top-level document rather than in an iframe. To address this use case Chrome has proposed an extension to the Storage Access API which adds arequestStorageAccessFor() method.

The requestStorageAccessFor() method

Browser Support

  • Chrome: 119.
  • Edge: 119.
  • Firefox: not supported.
  • Safari: not supported.

Source

requestStorageAccessFor() method works in a similar way to requestStorageAccess() but for top-level resources. It can only be used for sites within a Related Website Set to prevent granting general access to third-party cookies.

For more details on how to use requestStorageAccessFor() read the Related Website Sets: developer guide.

The top-level-storage-access permission query

Browser Support

  • Chrome: not supported.
  • Edge: not supported.
  • Firefox: not supported.
  • Safari: not supported.

Similar to the storage-access permission, there is a top-level-storage-access permission to check whether access can be granted for requestStorageAccessFor().

How is the Storage Access API different when used with RWS?

When Related Website Sets are used with the Storage Access API, certain additional capabilities are available as detailed in the following table:

Without RWS With RWS
Requires a user gesture to initiate the request for storage access
Requires user to visit requested storage origin in a top-level context before granting access
First time user prompt can be skipped
requestStorageAccess not required to be called if access has been previously granted
Automatically grants access across other domains in a Related Website Site
Supports requestStorageAccessFor for top-level page access
Differences between using Storage Access API without and with Related Website Sets

Demo: setting and accessing cookies

The following demo shows how a cookie set by yourself in the first screen of the demo can be accessed in an embedded frame in the second site of the demo:

storage-access-api-demo.glitch.me

The demo requires a browser with third-party cookies disabled:

  • Chrome 118 or higher with the chrome://flags/#test-third-party-cookie-phaseout flag set and browser restarted.
  • Firefox
  • Safari

Demo: setting Local Storage

The following demo shows how to access unpartitioned Broadcast Channels from a third-party iframe using the Storage Access API:

https://saa-beyond-cookies.glitch.me/

The demo requires Chrome 125 or higher with the test-third-party-cookie-phaseout flag enabled.

Resources