=== modified file 'src/com/goldencode/p2j/main/EmbeddedWebHandler.java'
--- src/com/goldencode/p2j/main/EmbeddedWebHandler.java	2023-10-05 16:22:12 +0000
+++ src/com/goldencode/p2j/main/EmbeddedWebHandler.java	2023-10-10 11:35:04 +0000
@@ -76,17 +76,14 @@
 import com.goldencode.p2j.util.logging.*;
 import com.goldencode.p2j.web.*;
 
-import javax.servlet.*;
 import javax.servlet.http.*;
 
 import org.eclipse.jetty.server.*;
 import org.eclipse.jetty.server.handler.*;
 import org.eclipse.jetty.util.resource.*;
 
-import java.io.*;
 import java.lang.*;
 import java.util.*;
-import java.util.logging.*;
 
 /**
  * Define handlers to run the embedded web app from within fwd.  The handlers are run on the
@@ -245,7 +242,7 @@
       Map<String, String> placeholderValuePairs = new HashMap<>();
       if (clientUrl != null)
       {
-         placeholderValuePairs.put(PLACEHOLDER_CLIENT_URL, clientUrl);
+         placeholderValuePairs.put(AUTO_LOGIN_DATA, clientUrl);
       }
       
       if (target.equals(TARGET_EMBEDDED_CONFIGS))

=== modified file 'src/com/goldencode/p2j/main/VirtualDesktopWebHandler.java'
--- src/com/goldencode/p2j/main/VirtualDesktopWebHandler.java	2023-10-08 10:26:10 +0000
+++ src/com/goldencode/p2j/main/VirtualDesktopWebHandler.java	2023-10-10 11:38:27 +0000
@@ -67,9 +67,9 @@
 import java.lang.*;
 import java.util.*;
 
-import javax.servlet.*;
 import javax.servlet.http.*;
 
+import com.fasterxml.jackson.databind.*;
 import com.goldencode.p2j.security.*;
 import com.goldencode.p2j.security.SecurityManager;
 import com.goldencode.p2j.util.logging.*;
@@ -318,7 +318,11 @@
          String clientUrl = spawnerResult != null ? spawnerResult.uri : null;
          if (clientUrl != null)
          {
-            placeholderValuePairs.put(PLACEHOLDER_CLIENT_URL, clientUrl);
+            placeholderValuePairs.put(AUTO_LOGIN_DATA,
+                                      new ObjectMapper().createObjectNode()
+                                                        .put("url", clientUrl)
+                                                        .put("storageId", spawnerResult.storageId)
+                                                        .toString());
          }
          
          placeholderValuePairs.put(PLACEHOLDER_TITLE, PAGE_TITLE_LOGIN == null ?

=== modified file 'src/com/goldencode/p2j/main/WebDriverHandler.java'
--- src/com/goldencode/p2j/main/WebDriverHandler.java	2023-10-05 16:22:12 +0000
+++ src/com/goldencode/p2j/main/WebDriverHandler.java	2023-10-10 11:56:50 +0000
@@ -127,7 +127,7 @@
    protected static final String PLACEHOLDER_TITLE = "${title}";
 
    /** Template placeholder for the newly spawned client url. */
-   protected static final String PLACEHOLDER_CLIENT_URL = "${spawnedClientUrl}";
+   protected static final String AUTO_LOGIN_DATA = "${autoLoginData}";
    
    /** Template placeholder for the html template. */
    protected static final String PLACEHOLDER_HTML_TEMPLATE = "${html}";
@@ -192,7 +192,7 @@
    static
    {
       PLACEHOLDER_VALUE_PAIRS.put("${themes}", getAvailableThemes());
-      PLACEHOLDER_VALUE_PAIRS.put(PLACEHOLDER_CLIENT_URL, "");
+      PLACEHOLDER_VALUE_PAIRS.put(AUTO_LOGIN_DATA, "");
    }
 
    /**
@@ -322,7 +322,13 @@
                  spawnerResult.uri,
                  driverType);
       }
-      writeUrlInResponse(spawnerResult.uri, base, response, spawnerResult.webClientUuid, spawnerResult.cookie, requestParameters.getReferrer());
+      writeUrlInResponse(spawnerResult.uri,
+                         spawnerResult.storageId,
+                         base,
+                         response,
+                         spawnerResult.webClientUuid,
+                         spawnerResult.cookie,
+                         requestParameters.getReferrer());
    }
    
    /**
@@ -347,6 +353,7 @@
       String pw = requestParameters.getPassword();
       String authBlob = null;
       String fwdUser = null;
+      String storageId = null;
       if (spawnParameters.isSso())
       {
          if (spawnParameters.getSsoAuthResult() != null)
@@ -354,6 +361,7 @@
             // auto login has already completed
             authBlob = spawnParameters.getSsoAuthResult().getAuthBlob();
             fwdUser = spawnParameters.getSsoAuthResult().getFwdUser();
+            storageId = spawnParameters.getSsoAuthResult().getPersistentUserStorageIdentifier();
          }
          else
          {
@@ -398,6 +406,7 @@
             LOG.log(Level.FINE, "Attempting spawn for SSO authenticated app user %s.", user);
 
             authBlob = ssoAuthResult.getAuthBlob();
+            storageId = ssoAuthResult.getPersistentUserStorageIdentifier();
             // replace in-app user & pass with os user & pass
             user = ssoUsers.osUser;
             pw = ssoUsers.osPass;
@@ -476,6 +485,7 @@
       try
       {
          result.uri = spawner.getRemoteUri();
+         result.storageId = storageId;
       }
       catch (URISyntaxException e)
       {
@@ -961,6 +971,8 @@
     * 
     * @param    remoteUri
     *           The redirect url provided with the authorization parameter.
+    * @param    storageId
+    *           The storage ID.
     * @param    base
     *           The base request.
     * @param    response
@@ -973,6 +985,7 @@
     *           The referrer header to be attached to the response.
     */
    private void writeUrlInResponse(String remoteUri,
+                                   String storageId,
                                    Request base,
                                    HttpServletResponse response,
                                    String webClientUuid,
@@ -989,10 +1002,15 @@
          response.addCookie(cookie);
       }
       
+      ObjectMapper mapper = new ObjectMapper();
+      ObjectNode responseJson = mapper.createObjectNode();
+      responseJson.put("url", remoteUri);
+      responseJson.put("storageId", storageId);
+      
       try
       {
          PrintWriter writer = response.getWriter();
-         writer.println(remoteUri);
+         writer.println(responseJson.toString());
          writer.flush();
       }
       catch (IOException e)
@@ -1195,6 +1213,9 @@
    {
       /** Redirect URI in case of a successful spawn. <code>null</code> on failure. */
       public String uri;
+      
+      /** Unique identifier for the local storage used by the user. */
+      public String storageId;
 
       /** The uuid of the spawned client. */
       public String webClientUuid;

=== modified file 'src/com/goldencode/p2j/main/fwd_sdk.js'
--- src/com/goldencode/p2j/main/fwd_sdk.js	2023-10-08 13:12:00 +0000
+++ src/com/goldencode/p2j/main/fwd_sdk.js	2023-10-10 10:57:06 +0000
@@ -145,7 +145,12 @@
             {
                if (httpRequest.responseText)
                {
-                  window.location.assign(httpRequest.responseText);
+                  const responseJson = JSON.parse(httpRequest.responseText);
+                  const launchedClientOrigin = new URL(responseJson.url).origin;
+                  window.top.postMessage(
+                     { origin: launchedClientOrigin, storageId: responseJson.storageId },
+                     window.top.location.origin);
+                  window.location.assign(responseJson.url);
                }
             }
             else
@@ -159,7 +164,7 @@
             showError(ex && Object.keys(ex).length > 0 ? JSON.stringify(ex) : MSG_SDK_DEFAULT_REQUEST_ERROR);
          }
       };
-      httpRequest.open('POST', window.parent.location.href);
+      httpRequest.open('POST', window.top.location.href);
       httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
       httpRequest.responseType = 'text';
       httpRequest.send(body ?? 'usr=' + encodeURIComponent(usernameNode.value) +

=== modified file 'src/com/goldencode/p2j/main/web_landing.html'
--- src/com/goldencode/p2j/main/web_landing.html	2023-09-15 06:15:45 +0000
+++ src/com/goldencode/p2j/main/web_landing.html	2023-10-10 11:57:36 +0000
@@ -70,7 +70,7 @@
    </head>
    <body id="main-body">
    <!-- The url for the iframe src --> 
-   <template id="spawned-client-url">${spawnedClientUrl}</template>
+   <template id="auto-login-data">${autoLoginData}</template>
    <!-- The html for the iframe srcdoc -->
    <template id="html">${html}</template>
    
@@ -81,12 +81,17 @@
       
       const htmlTemplate = document.getElementById('html');
 
-      const spawnedClientTemplate = document.getElementById('spawned-client-url');
-      const spawnedClientUrl = spawnedClientTemplate.content.textContent;
+      const autoLoginTemplate = document.getElementById('auto-login-data');
+      let isAutoLogin = autoLoginTemplate.content.textContent;
+      let spawnedClientUrl;
+      let autoLoginStorageId;
 
       const iFrame = document.getElementById('main-iframe');
-      if (spawnedClientUrl)
+      if (isAutoLogin)
       {
+         const autoLoginData = JSON.parse(autoLoginTemplate.content.textContent);
+         spawnedClientUrl = autoLoginData.url;
+         autoLoginStorageId = autoLoginData.storageId;
          iFrame.src = spawnedClientUrl;
       }
       else
@@ -95,7 +100,84 @@
       }
    
       htmlTemplate.remove();
-      spawnedClientTemplate.remove();
+      autoLoginTemplate.remove();
+      
+      (function()
+      {
+         let iframeOrigin = isAutoLogin ? new URL(spawnedClientUrl).origin : null;
+         // if client still not spawned, resolving is delayed to first cross-document msg.
+         let iframeWindow = isAutoLogin ? iFrame.contentWindow : null;
+         let storageId = autoLoginStorageId ?? "__default";
+
+         window.addEventListener('message', function (event)
+         {
+            if (iframeOrigin == null)
+            {
+               if (event.origin !== window.origin)
+               {
+                  console.warn('Message received from unknown origin. Expecting login, but found ' +
+                          event.origin);
+                  return;
+               }
+               iframeOrigin = event.data.origin;
+               iframeWindow = window.location.pathname.endsWith('embedded') ?
+                       iFrame.contentWindow.frames[0] : // or find '#embeddedP2J'
+                       iFrame.contentWindow;
+               
+               if (event.data.storageId)
+               {
+                  storageId = event.data.storageId;
+               }
+               console.log('The launched client has origin: ' + iframeOrigin);
+            }
+            else if (event.origin !== iframeOrigin)
+            {
+               console.warn('Message received from unknown origin. Expecting ' + iframeOrigin + ', but found ' +
+                       event.origin);
+            }
+            else
+            {
+               const userStorage = localStorage.getItem(storageId);
+               const userStorageJson = userStorage ? JSON.parse(userStorage) : {};
+
+               switch (event.data.type)
+               {
+                  case 'MSG_SET_KEY_VALUE':
+                     userStorageJson[event.data.key] = event.data.value;
+                     localStorage.setItem(storageId, JSON.stringify(userStorageJson));
+                     break;
+                  case 'MSG_GET_KEY_VALUE':
+                     const valueByKey = userStorageJson[event.data.key];
+                     iframeWindow.postMessage({
+                        msgId : event.data.msgId,
+                        type: event.data.type,
+                        value: valueByKey
+                     }, iframeOrigin);
+                     break;
+                  case 'MSG_DELETE_KEY_VALUE':
+                     delete userStorageJson[event.data.key];
+                     localStorage.setItem(storageId, JSON.stringify(userStorageJson));
+                     break;
+                  case 'MSG_GET_STORAGE_SIZE':
+                     const size = Object.keys(userStorageJson).length;
+                     iframeWindow.postMessage({
+                        msgId : event.data.msgId,
+                        type: event.data.type,
+                        value: size
+                     }, iframeOrigin);
+                     break;
+                  case 'MSG_GET_KEY':
+                     const keyByIndex = Object.keys(userStorageJson)[event.data.keyIndex];
+                     iframeWindow.postMessage({
+                        msgId : event.data.msgId,
+                        type: event.data.type,
+                        value: keyByIndex
+                     }, iframeOrigin);
+                     break;
+               }
+            }
+         });
+      }());
    </script>
    </body>
 </html>

=== modified file 'src/com/goldencode/p2j/security/SampleSsoAuthenticator.java'
--- src/com/goldencode/p2j/security/SampleSsoAuthenticator.java	2023-10-05 16:22:12 +0000
+++ src/com/goldencode/p2j/security/SampleSsoAuthenticator.java	2023-10-10 11:49:05 +0000
@@ -74,9 +74,6 @@
 {
    /** Cookie name used for auto-login. */
    private static final String SAMPLE_COOKIE_NAME = "SampleSsoAuthenticator";
-
-   /** Cookie value used for auto-login. */
-   private static final String SAMPLE_COOKIE_VALID_VALUE = "TestValue";
    
    /** Cookie invalid value used to invalidate the cookie. */
    private static final String SAMPLE_COOKIE_INVALID_VALUE = "Invalid";
@@ -86,9 +83,6 @@
 
    /** Example value for SESSION:AUTH-BLOB. */
    private static final String SAMPLE_AUTH_BLOB = "Bearer dfg978sdftgvsdfvvs879d9u0gvsdf";
-   
-   /** Cookie value used for auto-login. */
-   private static final String SAMPLE_STORAGE_IDENTIFIER = "User23536456";
 
    /** The FWD user returned by default for all in-app users. */
    private String defaultFwdUser = "newuser";
@@ -122,9 +116,15 @@
       String appPass = paramMap.get(FWD_SDK_LOGIN_PARAM_PASS)[0];
 
       // TODO: check credentials against an auth provider
-      Cookie cookie = getValidCookie();
+      Cookie cookie = new Cookie(SAMPLE_COOKIE_NAME, appUser);
+      cookie.setPath(SAMPLE_COOKIE_PATH);
+      cookie.setSecure(true);
       
-      return new Result(true, defaultFwdUser, SAMPLE_STORAGE_IDENTIFIER, SAMPLE_AUTH_BLOB, cookie);
+      return new Result(true,
+                        defaultFwdUser,
+                        "storage-" + appUser,
+                        SAMPLE_AUTH_BLOB,
+                        cookie);
    }
    
    /**
@@ -161,26 +161,32 @@
    @Override
    public Result authenticate(Cookie[] cookies, LicensingData licensingData)
    {
-      if (cookies != null && cookies.length > 0)
-      {
-         // read the cookie, query the auth provider
-         String authCookieValue = Arrays.stream(cookies)
-                                        .filter(cookie -> cookie.getName().equals(SAMPLE_COOKIE_NAME))
-                                        .findAny()
-                                        .map(Cookie::getValue)
-                                        .orElse(null);
-         
-         if (!SAMPLE_COOKIE_VALID_VALUE.equals(authCookieValue))
-         {
-            return new Result(false, WebDriverHandler.SupportedHttpCode.UNAUTHORIZED, null);
-         }
-
-         // TODO: check cookie value against an auth provider and receive the new cookie value
-         Cookie cookie = getValidCookie();
-         
-         return new Result(true, defaultFwdUser, SAMPLE_STORAGE_IDENTIFIER, SAMPLE_AUTH_BLOB, cookie);
-      }
-      return null;
+      if (cookies == null || cookies.length == 0)
+      {
+         return null;
+      }
+      // read the cookie, query the auth provider
+      String authCookieValue = Arrays.stream(cookies)
+                                     .filter(cookie -> cookie.getName().equals(SAMPLE_COOKIE_NAME))
+                                     .findAny()
+                                     .map(Cookie::getValue)
+                                     .orElse(null);
+      
+      if (authCookieValue == null || SAMPLE_COOKIE_INVALID_VALUE.equals(authCookieValue))
+      {
+         return new Result(false, WebDriverHandler.SupportedHttpCode.UNAUTHORIZED, null);
+      }
+
+      // TODO: check cookie value against an auth provider and receive the new cookie value
+      Cookie cookie = new Cookie(SAMPLE_COOKIE_NAME, authCookieValue);
+      cookie.setPath(SAMPLE_COOKIE_PATH);
+      cookie.setSecure(true);
+
+      return new Result(true,
+                        defaultFwdUser,
+                        "storage-" + authCookieValue,
+                        SAMPLE_AUTH_BLOB,
+                        cookie);
    }
 
    /**
@@ -222,17 +228,4 @@
    {
       return null;
    }
-
-   /**
-    * Returns the cookie to be returned to the browser and used in the next auth requests.
-    * 
-    * @return   See above.
-    */
-   private Cookie getValidCookie()
-   {
-      Cookie cookie = new Cookie(SAMPLE_COOKIE_NAME, SAMPLE_COOKIE_VALID_VALUE);
-      cookie.setPath(SAMPLE_COOKIE_PATH);
-      cookie.setSecure(true);
-      return cookie;
-   }
 }
\ No newline at end of file

=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js'
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2023-09-12 16:04:02 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2023-10-10 10:57:06 +0000
@@ -2912,6 +2912,8 @@
       
       // reset the last activity time
       idleTimer.reset(t1);
+
+      const topPageOrigin = new URL(logoutPage).origin;
       
       switch (message[0])
       {
@@ -3650,26 +3652,11 @@
             var key  = me.readStringBinaryMessageByLength(message, offset, keyLength);
             offset = offset + keyLength * 2;
             
-            var value = p2j.restoreObject(key, true);
-            var value = String(value);
-            var valueLength = value.length;
-            
-            // create the response message
-            var msg = new Uint8Array(1 + 4 + 4 + valueLength * 2);
-            
-            offset = 0;
-            msg[offset] = types.MSG_GET_KEY_VALUE;
-            offset += 1;
-
-            writeInt32BinaryMessage(msg, offset, msgId);
-            offset += 4;
-
-            writeInt32BinaryMessage(msg, offset, valueLength);
-            offset += 4;
-
-            writeStringBinaryMessage(msg, value, offset);
-            
-            send(msg);
+            window.top.postMessage({
+               msgId,
+               type: "MSG_GET_KEY_VALUE",
+               key: key,
+            }, topPageOrigin);
             break;
          case types.MSG_SET_KEY_VALUE:
             var offset = 1;
@@ -3687,8 +3674,13 @@
             offset = offset + 4;
 
             var value  = me.readStringBinaryMessageByLength(message, offset, valueLength);
-            
-            p2j.saveObject(key, value, true);
+
+            window.top.postMessage({
+               msgId,
+               type: "MSG_SET_KEY_VALUE",
+               key: key,
+               value: JSON.stringify(value),
+            }, topPageOrigin);
             break;
          case types.MSG_DELETE_KEY_VALUE:
             var offset = 1;
@@ -3700,8 +3692,12 @@
             offset = offset + 4;
 
             var key  = me.readStringBinaryMessageByLength(message, offset, keyLength);
-            
-            p2j.deleteObject(key, true);
+
+            window.top.postMessage({
+               msgId,
+               type: "MSG_DELETE_KEY_VALUE",
+               key: key,
+            }, topPageOrigin);
             break;
          case types.MSG_GET_KEY:
             var offset = 1;
@@ -3712,26 +3708,11 @@
             var keyIndex = me.readInt32BinaryMessage(message, offset);
             offset = offset + 4;
             
-            var key = localStorage.key(keyIndex);
-            key = String(key);
-            var keyLength = key.length;
-            
-            // create the response message
-            var msg = new Uint8Array(1 + 4 + 4 + keyLength * 2);
-            
-            offset = 0;
-            msg[offset] = types.MSG_GET_KEY;
-            offset += 1;
-
-            writeInt32BinaryMessage(msg, offset, msgId);
-            offset += 4;
-            
-            writeInt32BinaryMessage(msg, offset, keyLength);
-            offset += 4;
-
-            writeStringBinaryMessage(msg, key, offset);
-            
-            send(msg);
+            window.top.postMessage({
+               msgId,
+               type: "MSG_GET_KEY",
+               keyIndex: keyIndex,
+            }, topPageOrigin);
             break;
          case types.MSG_GET_STORAGE_SIZE:
             var offset = 1;
@@ -3739,22 +3720,10 @@
             var msgId = me.readInt32BinaryMessage(message, offset);
             offset = offset + 4;
             
-            var size = localStorage.length;
-            size = Integer(size);
-            
-            // create the response message
-            var msg = new Uint8Array(1 + 4 + 4);
-            
-            offset = 0;
-            msg[offset] = types.MSG_GET_STORAGE_SIZE;
-            offset += 1;
-
-            writeInt32BinaryMessage(msg, offset, msgId);
-            offset += 4;
-            
-            writeInt32BinaryMessage(msg, offset, size);
-            
-            send(msg);
+            window.top.postMessage({
+               msgId,
+               type: "MSG_GET_STORAGE_SIZE",
+            }, topPageOrigin);
             break;
          case types.MSG_GET_TEXT_WIDTHS:
             // text widths
@@ -5409,6 +5378,83 @@
          }
       }, true);
 
+      const localStorageOrigin = new URL(logoutPage).origin;
+      window.addEventListener('message', function (event)
+      {
+         if (event.origin !== localStorageOrigin)
+         {
+            return;
+         }
+
+         console.log(event.data);
+         var offset = 0;
+
+         switch (event.data.type)
+         {
+            case 'MSG_GET_KEY_VALUE':
+               var msgId = event.data.msgId;
+               var value = event.data.value;
+               value = String(value);
+               var valueLength = value.length;
+
+               // create the response message
+               var msg = new Uint8Array(1 + 4 + 4 + valueLength * 2);
+
+               msg[offset] = types.MSG_GET_KEY_VALUE;
+               offset += 1;
+
+               writeInt32BinaryMessage(msg, offset, msgId);
+               offset += 4;
+
+               writeInt32BinaryMessage(msg, offset, valueLength);
+               offset += 4;
+
+               writeStringBinaryMessage(msg, value, offset);
+
+               send(msg);
+               break;
+            case 'MSG_GET_STORAGE_SIZE':
+               // create the response message
+               var msgId = event.data.msgId;
+               var size = event.data.value;
+
+               var msg = new Uint8Array(1 + 4 + 4);
+
+               msg[offset] = types.MSG_GET_STORAGE_SIZE;
+               offset += 1;
+
+               writeInt32BinaryMessage(msg, offset, msgId);
+               offset += 4;
+
+               writeInt32BinaryMessage(msg, offset, size);
+
+               send(msg);
+               break;
+            case 'MSG_GET_KEY':
+               var key = String(event.data.value);
+               var keyLength = key.length;
+
+               // create the response message
+               var msgId = event.data.msgId;
+               var msg = new Uint8Array(1 + 4 + 4 + keyLength * 2);
+
+               offset = 0;
+               msg[offset] = types.MSG_GET_KEY;
+               offset += 1;
+
+               writeInt32BinaryMessage(msg, offset, msgId);
+               offset += 4;
+
+               writeInt32BinaryMessage(msg, offset, keyLength);
+               offset += 4;
+
+               writeStringBinaryMessage(msg, key, offset);
+
+               send(msg);
+               break;
+         }
+      });
+      
       /**
        * Sends ping and pong notifications to the server and starts the ping/pong watcher timer.
        */

=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.emain.js'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.emain.js	2023-10-05 16:22:12 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.emain.js	2023-10-10 10:57:06 +0000
@@ -378,6 +378,7 @@
 
       if (ifr.src.startsWith("https://"))
       {
+         // client is spawned
          var msgId = p2j.embedded.getNextMessageId();
 
          var args = 
@@ -391,6 +392,7 @@
       }
       else
       {
+         // login page
          p2j.embedded.setPageLoadedCallback(p2j.emain.pageLoaded);
          
          function showLoginForm()
@@ -416,15 +418,21 @@
             {
                if (xmlHttp.status === 200)
                {
-                  var fwd_url = xmlHttp.responseText;
-                  if (fwd_url.startsWith("null"))
+                  if (xmlHttp.responseText.startsWith("null"))
                   {
                      showLoginForm();
                      showError({ "error": "Could not connect to the FWD server!" } );
                   }
                   else
                   {
-                     ifr.src = fwd_url;
+                     const responseJson = JSON.parse(xmlHttp.responseText);
+                     const clientUrl = responseJson.url;
+                     const launchedClientOrigin = new URL(clientUrl).origin;
+                     window.top.postMessage(
+                        { origin: launchedClientOrigin, storageId: responseJson.storageId },
+                        window.top.location.origin);
+                     
+                     ifr.src = clientUrl;
 
                      // the main view is transparent at this point; however, we need to realize it here to
                      // work around a firefox bug (https://bugzilla.mozilla.org/show_bug.cgi?id=941146),

