Persisting data across liveview navigation

This solution is flawed and insecure. After giving the problem some thought, I came up with something more suitable for production:

Define a helper function for Liveviews.

defmodule MyAppWeb.LiveViewUtils do
  use MyAppWeb, :verified_routes
  import Phoenix.LiveView

  def push_cookie(socket, key, value) do
    push_event(socket, "fetch-cookies", %{
      method: "PUT",
      path: ~p"/cookies",
      token: Phoenix.Token.sign(socket, "cookie", {key, value})
    })
  end
end

Catch this event on the client side in assets/js/app.js and send a fetch request back to the server (to a regular controller).

window.addEventListener("phx:fetch-cookies", ({ detail }) => {
  const { path, method, token } = detail;
  fetch(path, {
    method,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ token }),
  });
});

Add a route for this request:

put "/cookies", MyAppWeb.CookiesController, :put

Define a controller.

defmodule MyAppWeb.CookiesController do
  use MyAppWeb, :controller

  def put(conn, %{"token" => token}) do
    case Phoenix.Token.verify(conn, "cookie", token, max_age: 60) do
      {:ok, {key, value}} ->
        conn
        |> fetch_session()
        |> put_session(key, value)
        |> send_resp(:ok, "")

      _ ->
        send_resp(conn, :unauthorized, "")
    end
  end
end

The approach above can be easily extended to accommodate the push_delete_cookie/2 functionality.