Storage Access API para contenido embebido
Cómo un documento embebido pide acceso a cookies sin particionar, qué implican la mediación del usuario y la compatibilidad, y cómo diseñar una alternativa si se deniega.
Quieres la documentación estructurada de Identidad?
Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.
La Storage Access API permite que un documento embebido pida al navegador acceso a sus cookies sin particionar, y en algunos navegadores a otro almacenamiento, en un contexto donde ese acceso está bloqueado o particionado. El documento embebido comprueba su estado actual con document.hasStorageAccess() y lo solicita con document.requestStorageAccess(). Quien decide el resultado es el navegador, no la página, normalmente tras un gesto del usuario y a veces tras un aviso. Una concesión es una excepción acotada para un documento embebido bajo un sitio de nivel superior, y la página necesita una ruta definida para los resultados denegados y no compatibles.
Qué decide la Storage Access API
Muchos navegadores separan o bloquean el estado al que puede acceder un documento embebido de terceros. Un widget de inicio de sesión, un formulario de pago, un servicio de comentarios o un chat de soporte pueden descubrir que las cookies establecidas cuando el usuario visitó su propio sitio no se envían desde dentro de la página de otro sitio. La Storage Access API es la forma estandarizada de que ese documento pregunte si ese estado puede volver a estar disponible. La descripción general de la Storage Access API en MDN y el borrador de especificación de PrivacyCG describen el modelo.
La palabra clave es solicitud. El documento embebido pide; no configura. El navegador aplica sus propias reglas para decidir si la solicitud está permitida, si hay que preguntar al usuario y qué interacción previa ha tenido el usuario con el sitio embebido. Esas reglas varían según el navegador y la versión, y pueden cambiar entre lanzamientos. Una página puede describir lo que pide, pero no puede prometer lo que verá el usuario.
La mediación del usuario es la razón por la que la API tiene esta forma. Una persona que navega por un sitio que embebe un servicio de terceros no ha elegido necesariamente compartir con ese sitio el estado guardado de ese servicio. Por eso el navegador pregunta, ya sea mediante un aviso que nombra el sitio embebido y la página en la que aparece, o mediante sus propias reglas sobre la interacción previa. Lo que registra la concesión es la decisión del usuario, no la preferencia de la página.
El alcance importa tanto como la decisión. Una solicitud concedida se aplica a ese documento embebido y al contexto de nivel superior en el que está embebido. No cambia lo que pueden leer otros marcos, no se traslada a otro sitio de nivel superior y no dice nada sobre otras API de almacenamiento ni sobre quién es la persona. Las cookies son el tema central de la API. Que se incluyan otros tipos de almacenamiento depende del navegador y de la versión, así que consulta la documentación del navegador que pruebes.
Las claves de partición, es decir, la mecánica con la que los navegadores separan el estado por sitio de nivel superior, se tratan en Partición del almacenamiento del navegador y privacidad. La Storage Access API se apoya en ese límite como una excepción y no lo sustituye. Para la pregunta más amplia de qué mecanismo de almacenamiento encaja con cada dato, consulta Cookies, localStorage e IndexedDB: dónde debe vivir el estado.
La API tampoco sirve para conocer a una persona ni para enlazar sesiones entre sitios. Existe para que un servicio embebido legítimo, como un widget de inicio de sesión o de pago con el que el usuario eligió interactuar, siga funcionando cuando el navegador limita el estado de terceros. Un documento que solicita acceso sin un motivo claro de cara al usuario no le da base para decidir y no sirve a la persona que usa la página.
Comprobar el estado y solicitar acceso
document.hasStorageAccess() devuelve una promesa que se resuelve con un booleano para el documento actual. Lee el estado actual y no pide nada, así que puede ejecutarse al cargar sin un gesto del usuario. Un resultado true significa que el documento tiene ahora acceso a sus cookies sin particionar. Puede deberse a que el acceso se concedió antes, a que el documento no está embebido o a que el navegador no restringe las cookies de terceros en esta configuración, de modo que un valor true por sí solo no prueba que haya habido una concesión.
document.requestStorageAccess() es la solicitud en sí. También devuelve una promesa, que se resuelve cuando se concede el acceso y se rechaza cuando no. Necesita activación transitoria del usuario, como un clic o una pulsación de tecla dentro del documento embebido, así que es de esperar que se rechace si se llama desde un temporizador o al cargar, salvo que el permiso ya se hubiera concedido antes, en cuyo caso algunos navegadores la resuelven sin gesto. La llamada también puede rechazarse cuando el usuario declina un aviso, cuando las reglas del navegador indican que la solicitud no está permitida o cuando se recuerda una denegación anterior. Trata el rechazo como un resultado normal, no como una excepción que ocultar. La referencia de requestStorageAccess() enumera las condiciones.
Una secuencia breve sirve para la mayoría de los widgets embebidos. Al cargar, detecta las funciones disponibles y llama a hasStorageAccess(). Si el resultado es true, continúa con la ruta normal con sesión iniciada. Si es false, muestra un control que explique lo que necesita el widget y llama a requestStorageAccess() solo desde el controlador de clic de ese control. Tras una promesa resuelta, recarga o vuelve a pedir el estado que depende de las cookies y confirma con hasStorageAccess() otra vez antes de mostrar contenido con sesión iniciada.
async function showAccountState(button) {
if (!('hasStorageAccess' in document)) return renderSignedOut('unsupported');
if (await document.hasStorageAccess()) return renderSignedIn();
button.hidden = false;
button.addEventListener('click', async () => {
try {
await document.requestStorageAccess();
return (await document.hasStorageAccess()) ? renderSignedIn() : renderSignedOut('denied');
} catch {
return renderSignedOut('denied');
}
});
}
Vuelve a llamar a hasStorageAccess() en visitas posteriores en lugar de suponer que una concesión anterior sigue vigente. Los navegadores recuerdan o hacen caducar las decisiones según su propio calendario, el usuario puede restablecer los permisos del sitio y un perfil puede borrarse. Un documento que comprueba su estado en cada carga parte de la respuesta actual del navegador y no arrastra una suposición obsoleta de una visita a otra. La guía de uso de la Storage Access API muestra el mismo patrón con más detalle.
También se aplican varias condiciones de la página. El documento embebido necesita un contexto seguro. Si el marco está en un sandbox, la página que lo contiene debe permitir el token de sandbox de acceso al almacenamiento (allow-storage-access-by-user-activation) junto con los tokens que necesite el script, como allow-scripts y allow-same-origin. Una Permissions Policy también puede restringir la función storage-access para un marco. Cuando una solicitud se rechaza de inmediato, revisa los atributos del marco y la política de la página que lo contiene antes de suponer que un usuario tomó una decisión.
Cuando el navegador lo admite, la Permissions API informa de un permiso storage-access como concedido o pendiente de pregunta; la especificación no revela un estado denegado, así que una solicitud declinada se lee como pendiente de pregunta. Sirve para leer el estado antes de pedir, no para cambiarlo. La compatibilidad con esa consulta varía según el navegador, así que trátala como una señal opcional y mantén hasStorageAccess() como el estado en el que te basas para actuar.
Una concesión no reescribe las reglas de las cookies. Una cookie que debe viajar en un contexto entre sitios necesita SameSite=None y Secure en los navegadores que aplican las reglas SameSite a la solicitud, y la revisión debe registrar los atributos que observa. Si el widget sigue mostrándose sin sesión después de que hasStorageAccess() devuelva true, comprueba los atributos de la cookie y el origen de la solicitud antes de sospechar de la API.
Diferencias entre navegadores y compatibilidad
El comportamiento de los navegadores es la parte de este tema que más cambia. Los navegadores basados en Chromium, Firefox y Safari incluyen la API, pero difieren en cuándo aparece un aviso, en si importa la interacción previa con el sitio embebido como página de nivel superior, en cuánto tiempo se recuerda una decisión y en qué almacenamiento incluye la concesión. Algunos navegadores también aplican sus propias heurísticas o relaciones entre sitios que pueden conceder o denegar el acceso sin un aviso visible. Son decisiones del navegador, y un script de la página no puede forzarlas.
Trata la compatibilidad como algo que se mide por navegador y versión. Una comprobación de funciones como 'requestStorageAccess' in document te dice que el método existe. No te dice si la llamada mostrará un aviso, se resolverá en silencio o se rechazará. Consulta las tablas de compatibilidad de MDN y la guía de los fabricantes, como la guía de Chrome para la Storage Access API, y registra la versión que probaste, porque la misma página puede comportarse de otra forma tras una actualización del navegador.
Los navegadores también difieren en su postura por defecto ante las cookies de terceros. Algunos las bloquean o las particionan por defecto, otros dejan la decisión al usuario, y la política de una empresa puede cambiar de nuevo el resultado. En un navegador que no restringe las cookies de terceros, hasStorageAccess() puede devolver true sin ninguna solicitud. En un navegador que sí las restringe, la misma página necesita la solicitud. El resultado de una prueba en una configuración no describe la otra, y por eso el registro de la revisión nombra el navegador y sus ajustes.
El sitio embebido y el sitio de nivel superior forman parte de la decisión. El usuario puede ver un aviso que nombra a ambos, y una concesión para una pareja no dice nada sobre otra. Si el mismo widget aparece en varios sitios que operas, prevé probar y explicar cada pareja, y prevé que los usuarios vean la solicitud más de una vez.
No interpretes una concesión exitosa como prueba de que el almacenamiento de terceros no está particionado en general. La concesión es una excepción para un documento embebido, creada porque un usuario realizó una acción deliberada con un servicio que eligió usar. Lo que ocurre con otros marcos, otros sitios y visitas posteriores sigue siendo lo que dicen las reglas de partición del navegador. Si una función solo funciona en una prueba porque se concedió acceso, el diseño depende de una excepción, y el producto debería declarar esa dependencia en su propia documentación.
Diseñar para resultados denegados y no compatibles
Hay tres resultados que necesitan una ruta diseñada: concedido, denegado y no compatible. Concedido continúa con el estado normal con sesión iniciada. Denegado significa que el usuario declinó, que el navegador rechazó la llamada o que se recordó una denegación anterior. No compatible significa que faltan los métodos o que el navegador trata la función de otra manera. Cada uno de los dos últimos necesita un estado visible y funcional, no un marco en blanco ni un banner de error.
La alternativa más fiable es una ruta de primera parte. El widget embebido muestra una vista sin sesión con una acción clara que abre el servicio en su propia ventana o pestaña, donde el navegador aplica las reglas de primera parte. Tras iniciar sesión, el usuario vuelve a la página que contiene el widget, y este usa un estado que no depende de una cookie de terceros, por ejemplo un valor de corta duración entregado mediante un mensaje que el receptor comprueba contra el origen esperado.
Mantén útil el estado sin sesión. El contenido público debe mostrarse, los borradores que el usuario haya escrito deben conservarse y la interfaz debe decir con claridad qué falta: el servicio necesita permiso para usar su sesión guardada dentro de esta página, y el usuario puede continuar sin él. No preguntes de forma repetida. Tras una denegación, ofrece la acción de primera parte y deja que el usuario decida cuándo volver a intentarlo, porque una llamada repetida puede rechazarse sin aviso de todos modos.
Escribe la explicación antes del clic, no después de que el navegador responda. El texto junto al control debe decir qué podrá usar el servicio embebido, que el navegador pedirá confirmación con sus propias palabras y qué puede hacer el usuario si la rechaza. Que sea breve y evita redacciones que presenten el aviso del navegador como algo que el usuario debe aceptar.
No construyas la solución en torno a un aviso. Una página no puede responder, ocultar ni suprimir un aviso del navegador, y no debe intentar provocar uno fuera de una acción genuina del usuario. No describas el aviso a los usuarios como necesario para que el servicio funcione cuando existe una ruta de primera parte. La redacción y el momento del aviso pertenecen al navegador. La parte de la página es la explicación que se muestra antes del clic, que debe decir qué podrá leer el servicio embebido y por qué.
Usa la detección de funciones y el manejo de fallos en lugar de comprobar el user agent. Decide según si los métodos existen y según el resultado de la promesa, no según el nombre o la versión del navegador, de modo que una actualización que añada o cambie la compatibilidad no exija un cambio de código. Registra para tu propio diagnóstico la categoría del resultado, como concedido, denegado, no compatible o rechazado sin gesto, y mantenla libre de valores de cookies y de identificadores de cuenta.
Revisar un widget embebido propio
Prueba la API con un widget propio, embebido en un sitio de nivel superior de prueba que también sea tuyo, de modo que controles ambos orígenes y las cookies. Usa dos dominios registrables distintos, o dos nombres de host locales que el navegador trate como sitios separados, para que el marco sea realmente entre sitios. Una página de prueba en un subdominio que embebe otro subdominio del mismo dominio registrable es del mismo sitio y no ejercita la restricción.
Registra las condiciones de cada ejecución en lugar de suponer paridad entre navegadores: el nombre y la versión del navegador, el sitio de nivel superior, el origen embebido, los atributos SameSite y Secure de la cookie sometida a prueba, si el iframe está en un sandbox o tiene un atributo allow, si hubo un gesto del usuario antes de la llamada, el resultado observado de hasStorageAccess(), el resultado de la llamada y, cuando esté disponible, el estado del permiso. Dos ejecuciones con registros distintos son experimentos distintos.
Empieza cada ejecución desde un estado de cookies conocido. La gestión de cookies describe cómo se precargan las cookies para una sesión del navegador, y el aislamiento de cuentas en el navegador describe cómo mantener los contextos separados. Aquí importa partir de un estado limpio porque una cookie que quedó de una ejecución anterior puede hacer que una ruta denegada parezca una concedida.
BotBrowser soporta --bot-cookies, que inyecta cookies al arrancar o por BrowserContext, de modo que cada contexto de prueba puede partir de su propio estado de cookies documentado mientras se revisa un flujo embebido propio. BotBrowser no concede ni deniega solicitudes de la Storage Access API, no responde ni suprime los avisos de permisos del navegador y no cambia qué documentos embebidos permite el navegador usar almacenamiento sin particionar; esos resultados quedan en manos del navegador y del usuario.
Ejecuta el caso concedido con un gesto real del usuario y una decisión real en el navegador que pruebas. Si el aviso no puede responderse en una ejecución automatizada, haz ese caso a mano y regístralo como resultado manual. No sustituyas una concesión por una cookie inyectada, porque eso probaría la pantalla con sesión iniciada y no diría nada sobre la solicitud.
Interpreta cada resultado de forma estricta. Una ejecución concedida demuestra que esta versión del navegador permitió este origen embebido bajo este sitio de nivel superior tras este gesto. No demuestra cómo se comporta ningún otro navegador, ni que otros marcos puedan leer la cookie, ni que el almacenamiento de terceros esté abierto en general.
Repite la matriz tras una versión mayor del navegador, un cambio en los atributos de tus cookies, un cambio en los atributos o las políticas del marco en la página que lo contiene y un cambio en el flujo de inicio de sesión del widget. El registro de la última ejecución aceptada es la referencia, y una diferencia en el comportamiento del navegador es un hallazgo que hay que leer, no un fallo que esconder tras un reintento.
Ejecuta las comprobaciones de acceso al almacenamiento
Ejecuta estas comprobaciones en un widget embebido propio, en cada navegador y versión que admitas, y registra un resultado de superada o fallida para cada una.
- Estado frente a solicitud. Se supera si la página llama a
hasStorageAccess()al cargar sin mostrar ningún aviso, llama arequestStorageAccess()solo desde un controlador de clic y el registro muestra ambos resultados por separado. Falla si la solicitud se ejecuta al cargar o si los dos resultados se mezclan. - Gesto y rechazo. Partiendo de un estado sin concesión previa, llama a la solicitud una vez sin gesto del usuario y otra vez con uno. Se supera si la primera llamada se trata como un rechazo con un estado sin sesión visible y la segunda informa de su resultado real.
- Ruta concedida. Tras un resultado concedido, confirma que
hasStorageAccess()devuelvetruey que el widget muestra su estado con sesión iniciada usando la cookie esperada. Falla si el estado con sesión iniciada aparece mientrashasStorageAccess()esfalse. - Ruta denegada. Declina el aviso o usa una configuración en la que la llamada se rechaza. Se supera si el widget muestra una alternativa definida de primera parte o sin sesión, conserva el contenido público y los borradores escritos, y no vuelve a pedir acceso por su cuenta.
- Ruta no compatible. En un navegador o una configuración donde faltan los métodos, se supera si el widget llega a la misma alternativa definida mediante detección de funciones y no decide según el nombre del navegador.
- Registro del entorno. Se supera si el registro indica el navegador y la versión, el sitio de nivel superior, el origen embebido, los atributos
SameSiteySecure, los ajustes de sandbox y deallow, y el estado del permiso observado. Falla si se informa de un resultado sin ellos o si se da por supuesto que vale para otro navegador. - Alcance de una concesión. Embebe el mismo widget bajo un segundo sitio de nivel superior de prueba. Se supera si ese sitio obtiene su propio resultado y no se supone que la concesión del primero se aplique.
Fuentes
Artículos Relacionados
Lleva BotBrowser de la investigación a producción
Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.