Tableau embed report asking for login instead of directly loading the report in safari browser

I am working on a project in ReactJs in which I have embedded tableau reports. I have use connected apps direct trust with JWT so the reports does not require signin before loading and they are loading without signin in chrome and firefox however they require signin to tableau cloud in safari browser.

This is the error I get in console.
[Error] Failed to load resource: the server responded with a status of 404 () (tableau.embedding.3.12.0-pre.25.min.js.map, line 0)
[Error] Failed to load resource: the server responded with a status of 401 () (viewing, line 0)

import TableauViz from "@/components/TableauViz/TableauViz";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";

const Report = () => {
   const [device, setDevice] = useState("desktop");

   const { selectedReport = null, reportToken = "" } = useSelector(
      (state) => state.reports
   );

   const { isLargeScreenSidebarOpen } = useSelector((state) => state.ui);

   useEffect(() => {
      const handleResize = () => {
         if (window.innerWidth < 768) {
            setDevice("mobile");
         } else {
            setDevice("desktop");
         }
      };

      // Initial check
      handleResize();

      // Add event listener for window resize
      window.addEventListener("resize", handleResize);

      // Clean up the event listener on component unmount
      return () => {
         window.removeEventListener("resize", handleResize);
      };
   }, []);

   if (!selectedReport) return <></>;

   const options = {
      toolbar: "bottom",
      "hide-tabs": true,
      device,
      "hide-edit-button": true,
      width: "100%",
   };

   return (
      <TableauViz
         src={selectedReport.embeddedLink}
         options={options}
         token={reportToken}
      />
   );
};

export default Report;
import React, { useEffect, useRef, useState } from "react";
import { TableauEventType } from "https://public.tableau.com/javascripts/api/tableau.embedding.3.latest.min.js";
import { ErrorMessage } from "@/components/ErrorMessage/ErrorMessage";

const TableauViz = ({ src, options, token }) => {
   const vizContainer = useRef(null);
   const [error, setError] = useState("");

   function handleError(err) {
      try {
         if (err.detail) {
            const details = JSON.parse(err.detail.message);
            console.error(details);
            if (details.statusCode === 401) {
               setError("You are not authorized to view this report.");
               emptyVizContainer();
            } else {
               setError("Something went wrong.");
               emptyVizContainer();
            }
         }
      } catch (error) {
         console.error("handleError", error);
         setError("Something went wrong.");
         emptyVizContainer();
      }
   }

   function emptyVizContainer() {
      if (vizContainer.current) {
         vizContainer.current.innerHTML = "";
      }
   }

   useEffect(() => {
      // Initialize the Tableau Viz web component
      const vizElement = document.createElement("tableau-viz");
      vizElement.id = "tableauViz";
      vizElement.src = src;
      vizElement.token = token;

      // Add options as attributes
      for (const [key, value] of Object.entries(options)) {
         vizElement.setAttribute(key, value);
      }

      // Append the viz element to the container
      if (vizContainer.current) {
         vizContainer.current.innerHTML = "";
         vizContainer.current.appendChild(vizElement);
      }

      // Add event listeners
      vizElement.addEventListener(TableauEventType.VizLoadError, handleError);


      // Cleanup event listeners on unmount
      return () => {
         vizElement.removeEventListener(
            TableauEventType.VizLoadError,
            handleError
         );
      };
   }, [src, options]);

   if (error)
      return (
         <div className="h-100 d-flex align-items-center justify-content-center">
            <ErrorMessage message={error} />
         </div>
      );

   return <div ref={vizContainer} className="tableau-viz-container m-auto" />;
};

export default TableauViz;

In the official documentation they say it is because safari blocks third party cookies the report is asking for signin but they don’t provide a solution. I tried block third party cookies in chrome but still the report were loading fine.

Safari blocks third-party cookies by default, which breaks Tableau’s JWT-based connected apps when embedded as a third-party iframe. That’s why it asks for a sign-in only in Safari.

Quick solutions:

  1. Use First-Party Embedding
  • Host the embedding page on the same domain as Tableau Cloud (not practical for Tableau-hosted environments).
  1. Prompt users to allow third-party cookies (not user-friendly, especially in Safari).
  2. Use Safari’s Storage Access API
  • It’s the only official workaround to request storage access for third-party iframes.
  • Tableau doesn’t support it out-of-the-box yet, so you’d need a custom implementation.
  1. Best workaround:
    Open the report once in a new tab (first-party) to set cookies, then return to embedded view.

There’s no full fix without Tableau’s support for Storage Access API or a backend proxying approach to make it first-party.

Let me know if you want code for any workaround.