# Storage Access API: third-party cookies in iframes

> How hasStorageAccess() and requestStorageAccess() let embedded cross-site content reach third-party cookies browsers block by default, and the gesture required.

**In one line:** 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," for browsers that block unpartitioned third-party cookies by default.

## The problem it solves

Browsers restrict access to unpartitioned third-party cookies — "all cookies for a site
stored in one shared jar" — in a third-party `<iframe>` context to prevent cross-site
tracking. That breaks legitimate cases such as single sign-on with a federated identity
provider or a personalization service embedded across multiple related sites. The Storage
Access API is, per MDN, "intended to solve this problem" without requiring users to disable
third-party cookie blocking outright.

## Checking and requesting access

```js
const hasAccess = await document.hasStorageAccess();
if (!hasAccess) {
  await document.requestStorageAccess();
}
```

`Document.hasStorageAccess()` resolves to a boolean indicating whether the document already
has access to third-party cookies. `Document.requestStorageAccess()` requests the
`storage-access` permission and resolves if granted, or rejects if denied.
`Document.hasUnpartitionedCookieAccess()` is documented as the new name for
`hasStorageAccess()`.

## Transient activation is required

Per MDN: "`requestStorageAccess()` requests are automatically denied unless the embedded
content is currently processing a user gesture such as a tap or click (transient
activation), or if permission was already granted previously." That is why a real
integration calls it from inside a click handler rather than on page load.

## Feature detection and fallback

```js
function doThingsWithCookies() {
  document.cookie = "foo=bar";
}

async function handleCookieAccess() {
  if (!("requestStorageAccess" in document)) {
    // Storage Access API unsupported here — fall back to hoping cookies work,
    // as recommended by MDN for browsers without this API.
    doThingsWithCookies();
    return;
  }
  const hasAccess = await document.hasStorageAccess();
  if (hasAccess) {
    doThingsWithCookies();
    return;
  }
  btn.addEventListener("click", async () => {
    try {
      await document.requestStorageAccess();
      doThingsWithCookies();
    } catch (err) {
      console.error(`Error obtaining storage access: ${err}. Please sign in.`);
    }
  });
}
```

## Sandboxed iframes need an explicit token

A sandboxed `<iframe>` must carry the `allow-storage-access-by-user-activation` sandbox
token (along with `allow-scripts` and `allow-same-origin`) for a `requestStorageAccess()`
call from inside it to succeed:

```html
<iframe
  sandbox="allow-storage-access-by-user-activation
                allow-scripts
                allow-same-origin"
>
  …
</iframe>
```

## Grant scope and re-activation

A grant is keyed by `<top-level site, embedded site>` — MDN gives the example of embedding
`locator.example.com` on `embedder.com`: the grant covers "any subdomain of `example.com`
embedded on any page of `embedder.com`." Even after a grant exists, each new browsing
context (a new tab, or a fresh iframe instance) must call `requestStorageAccess()` again to
activate it there — though MDN notes that call "won't require transient activation once
already granted." A same-origin self-navigation or reload after being granted access carries
the access over without a new call.

## Requirements that can cause a rejection

MDN lists several conditions under which `requestStorageAccess()` is denied: the document
and top-level document must not have a `null` origin; the window must be a secure context
(HTTPS); the embedded origin must have interacted with the browser as first-party recently;
and access "can be blocked by a `storage-access` Permissions Policy header set by the
server." MDN also notes the document "may also be required to pass additional
browser-specific checks" such as allowlists, blocklists, or user settings.

## Support

MDN documents `Document.hasStorageAccess`, `Document.hasUnpartitionedCookieAccess`,
`Document.requestStorageAccess`, and the non-standard, deprecated
`Document.requestStorageAccessFor` each with their own browser compatibility table; check
those tables for the current per-browser support position before depending on this API in
production.

## Practical checklist

- [ ] Feature-detect with `if (!document.hasStorageAccess)` before calling any method — MDN's
      own example falls back to just trying the cookie operation when the API is absent.
- [ ] Call `requestStorageAccess()` from inside a user-gesture event handler (e.g. a click),
      not on page load — it is denied outside transient activation unless already granted.
- [ ] Wrap `requestStorageAccess()` in `try...catch`; the returned promise rejects when the
      user denies access or the gesture requirement is not met.
- [ ] Add the `allow-storage-access-by-user-activation` sandbox token to a sandboxed
      `<iframe>` that needs to call this API, alongside `allow-scripts` and
      `allow-same-origin`.
- [ ] Re-call `requestStorageAccess()` in each new tab or iframe instance even after a grant
      exists elsewhere for the same `<top-level site, embedded site>` pair.
- [ ] Note that `Document.requestStorageAccessFor()` is non-standard and deprecated; it lets
      a top-level site request access, for an embed in the same related website set, on
      behalf of that embed instead of the embed calling the API itself.

## Cross-references

- [Storage persistence](/reference/storage/persistence/) — a related storage guarantee
- [Storage eviction](/reference/storage/eviction/) — a related storage lifecycle guarantee