diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js
index ba3b561ad082517a325cee6c3d5fabd837b4038e..2fbf2c28cb1f006a6bc9cb732d7e6694ebf25f73 100644
--- a/javascript/src/iframe/viamapi-iframe.js
+++ b/javascript/src/iframe/viamapi-iframe.js
@@ -47,6 +47,7 @@ import {
   checkRecoveryKeyCombine,
   encryptShare
 } from "../utilities/secrets";
+import { generateNonce, signRSA } from "../utilities/cryptoUtils";
 
 const penpalMethods = require("../../temp/penpal-methods").default;
 const WopiAPI = require("./wopiapi-iframe");
@@ -129,6 +130,23 @@ function setIdentityInLocalStorage(identityToStore, extendKey = true) {
   );
 }
 
+async function setCurrentlyLoadedIdentity(identity) {
+  if (identity) {
+    const nonce = generateNonce();
+    const privateKey = identity.authentication.privateKey;
+    const nonceSignature = await signRSA(privateKey, nonce);
+    window.viamApi.setNonce(Buffer.from(nonce).toString("base64"));
+    window.viamApi.setNonceSignature(
+      Buffer.from(nonceSignature).toString("base64")
+    );
+  } else {
+    window.viamApi.setNonce("");
+    window.viamApi.setNonceSignature("");
+  }
+
+  window.currentlyLoadedIdentity = identity;
+}
+
 function getProfileData(identity) {
   return new Penpal.Promise(executeResultUpper => {
     executeRestfulFunction(
@@ -260,7 +278,7 @@ const destroyIdentity = () => {
     const { publicKey } = window.currentlyLoadedIdentity.authentication;
 
     delete window.loadedIdentities[publicKey];
-    window.currentlyLoadedIdentity = null;
+    setCurrentlyLoadedIdentity(null);
     destroyIdentityFromLocalStorage(publicKey);
   }
 };
@@ -390,10 +408,17 @@ function loadIdentityInternal(identityKey, pinCode) {
               "Please restore or authorize your account via another device."
           });
         }
+        if (!loadedIdentity.authentication.privateKey) {
+          result({
+            data: "",
+            code: "400",
+            status: "No privateKey"
+          });
+        }
         localStorage.removeItem("attempt");
 
         window.loadedIdentities[identityKey] = loadedIdentity;
-        window.currentlyLoadedIdentity = loadedIdentity;
+        await setCurrentlyLoadedIdentity(loadedIdentity);
 
         if (identityKey === localStorage.getItem("authenticatedIdentity")) {
           window.currentlyAuthenticatedIdentity = loadedIdentity;
@@ -479,10 +504,10 @@ function getCertificateForPassport(passportUUID, internal) {
 
             getProfileData(passportIdentity).then(executeResult1 => {
               setIdentityInLocalStorage(passportIdentity)
-                .then(() => {
+                .then(async () => {
                   window.currentlyAuthenticatedIdentity = passportIdentity;
                   window.lastTimeGetProfile = 0;
-                  window.currentlyLoadedIdentity = passportIdentity;
+                  await setCurrentlyLoadedIdentity(passportIdentity);
                   const copyOfCryptoData = JSON.parse(
                     JSON.stringify(cryptoData)
                   );
@@ -529,7 +554,7 @@ function getCertificateForPassport(passportUUID, internal) {
 const connection = Penpal.connectToParent({
   // Methods child is exposing to parent
   methods: {
-    initialize: (apiUrl, wopiUrl, collaboraUrl) => {
+    initialize: async (apiUrl, wopiUrl, collaboraUrl) => {
       if (!apiUrl) {
         apiUrl = `${window.location.origin}/api/`;
         console.warn(`API host URL not specified. Fall back to ${apiUrl}`); // eslint-disable-line no-console
@@ -555,11 +580,40 @@ const connection = Penpal.connectToParent({
         collaboraUrl.charAt(collaboraUrl.length - 1) === "/"
           ? collaboraUrl
           : collaboraUrl + "/";
+
+      const {
+        code,
+        data: { domains: permittedDomains }
+      } = await penpalMethods.identityGetPermittedDomains();
+
+      if (code !== "200") {
+        throw new Error("Unable to retrieve a list of permitted domains.");
+      }
+
+      const iframeOrigin = document.referrer;
+      if (
+        iframeOrigin && // Empty iframe origins are allowed. This is the case for Roundcube plugin
+        permittedDomains &&
+        permittedDomains.length
+      ) {
+        let iframeOriginIsPermitted = false;
+
+        for (const domain of permittedDomains) {
+          if (iframeOrigin.includes(domain)) {
+            iframeOriginIsPermitted = true;
+            break;
+          }
+        }
+
+        if (!iframeOriginIsPermitted) {
+          throw new Error(`Iframe origin "${iframeOrigin}" is not permitted.`);
+        }
+      }
     },
     ...penpalMethods,
     createIdentity(pinCode) {
       return new Penpal.Promise(result => {
-        createPassportCertificate(makeid()).then(function (keys) {
+        createPassportCertificate(makeid()).then(async function (keys) {
           const newIdentity = new Identity();
           const cryptoData = new CryptoData();
           cryptoData.setPublicKey(keys["publicKeyPEM"]);
@@ -568,7 +622,7 @@ const connection = Penpal.connectToParent({
           newIdentity.setAuthentication(cryptoData);
           newIdentity.setPinCode(pinCode);
 
-          window.currentlyLoadedIdentity = newIdentity;
+          await setCurrentlyLoadedIdentity(newIdentity);
           localStorage.setItem(
             "currentlyLoadedIdentity",
             JSON.stringify(newIdentity)
@@ -629,7 +683,7 @@ const connection = Penpal.connectToParent({
           identity.pinCode = newPinCode;
           await setIdentityInLocalStorage(identity);
           window.currentlyAuthenticatedIdentity = identity;
-          window.currentlyLoadedIdentity = identity;
+          await setCurrentlyLoadedIdentity(identity);
 
           return encodeResponse("200", null, "Successfully changed pincode");
         } else {
@@ -758,7 +812,7 @@ const connection = Penpal.connectToParent({
           let sequence = Promise.resolve();
           if (executeResult.code === "200") {
             sequence = sequence.then(() => {
-              setIdentityInLocalStorage(registerIdentity);
+              setIdentityInLocalStorage(window.currentlyLoadedIdentity);
             });
           }
           sequence
@@ -791,6 +845,7 @@ const connection = Penpal.connectToParent({
       });
     },
     login: async (loginIdentity, mode, requestCode, requestActionID) => {
+      const localStorageIdentity = getIdentityFromLocalStorage();
       if (!window.loadedIdentities[loginIdentity.authentication.publicKey]) {
         return {
           data: "",
@@ -995,7 +1050,7 @@ const connection = Penpal.connectToParent({
         "currentlyLoadedIdentity"
       );
       const identity = new Identity(currentlyLoadedIdentity);
-      window.currentlyLoadedIdentity = identity;
+      await setCurrentlyLoadedIdentity(identity);
       const { publicKey } = identity.authentication;
       window.loadedIdentities[publicKey] = identity;
       window.viamAnonymousApi.setIdentity(publicKey);
@@ -1577,7 +1632,7 @@ const connection = Penpal.connectToParent({
       return encodeResponse("200", "enabled", "OK");
     },
     /**
-     * 
+     *
      * @param passportUUID
      * @param documentUUID
      * @param documentContentType
@@ -1609,7 +1664,7 @@ message SignatureData {
   uint32 pageNumber = 3;
   Size pageSize = 4;
 }
-     * 
+     *
      */
     signDocumentJava: async (
       passportUUID,
@@ -2489,7 +2544,7 @@ connection.promise.then(parent => {
     if (event.key === "authenticatedIdentity" && event.newValue === null) {
       const publicKey =
         window.currentlyAuthenticatedIdentity.authentication.publicKey;
-      window.currentlyLoadedIdentity = null;
+      setCurrentlyLoadedIdentity(null);
       window.currentlyAuthenticatedIdentity = null;
       const event = createEvent("LogoutFromAnotherTab", "Logout", [publicKey]);
       parent.onEvent(event);
@@ -2572,7 +2627,8 @@ connection.promise.then(parent => {
           false
         );
 
-        window.currentlyLoadedIdentity = identity;
+        !window.currentlyLoadedIdentity &&
+          (await setCurrentlyLoadedIdentity(identity));
 
         if (!identityAuthenticatedEvent && identity) {
           const event = createEvent("IdentityAuthenticated", "Authenticated", [
@@ -2604,7 +2660,7 @@ connection.promise.then(parent => {
         }
 
         identityAuthenticatedEvent = false;
-        window.currentlyLoadedIdentity = null;
+        setCurrentlyLoadedIdentity(null);
       }
 
       localStorage.removeItem("currentlyLoadedIdentity");
@@ -2711,7 +2767,7 @@ connection.promise.then(parent => {
               localStorage.removeItem("token");
               localStorage.removeItem("authenticatedIdentity");
               delete window.loadedIdentities[authenticationPublicKey];
-              window.currentlyLoadedIdentity = null;
+              setCurrentlyLoadedIdentity(null);
               window.currentlyAuthenticatedIdentity = null;
               window.lastTimeGetProfile = 0;
 
diff --git a/javascript/src/utilities/cryptoUtils.js b/javascript/src/utilities/cryptoUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..cee822966828071966dd6a7c5c66f2acb17b8561
--- /dev/null
+++ b/javascript/src/utilities/cryptoUtils.js
@@ -0,0 +1,45 @@
+const webcryptoLiner = require("webcrypto-liner/build/index");
+
+export const generateNonce = () => {
+  return webcryptoLiner.crypto.getRandomValues(new Buffer(12));
+}
+
+const convertPemToBinary = (pem) => {
+  const lines = pem.split("\n");
+  let encoded = "";
+  for (let i = 0; i < lines.length; i++) {
+    if (
+      lines[i].trim().length > 0 &&
+      lines[i].indexOf("-BEGIN PRIVATE KEY-") < 0 &&
+      lines[i].indexOf("-BEGIN PUBLIC KEY-") < 0 &&
+      lines[i].indexOf("-END PRIVATE KEY-") < 0 &&
+      lines[i].indexOf("-END PUBLIC KEY-") < 0
+    ) {
+      encoded += lines[i].trim();
+    }
+  }
+  return Buffer.from(encoded, "base64")
+};
+
+export const signRSA = async (privateKeyPEM, data) => {
+  const privateKey = await webcryptoLiner.crypto.subtle.importKey(
+    "pkcs8",
+    convertPemToBinary(privateKeyPEM),
+    {
+      name: "RSA-PSS",
+      hash: "SHA-256"
+    },
+    true,
+    ["sign"]
+  );
+
+  return await webcryptoLiner.crypto.subtle.sign(
+    {
+      name: "RSA-PSS",
+      // hash: "SHA-256",
+      saltLength: 32
+    },
+    privateKey,
+    data
+  );
+};
diff --git a/main.go b/main.go
index 6d931629ef40a58c49882b40be4f203a03e4dd4f..a3c4b5aef0f2eaddf481043d4119fbed096dd86b 100644
--- a/main.go
+++ b/main.go
@@ -76,12 +76,15 @@ func buildViamAPI() string {
 	keysLen := len(keys)
 
 	result += "function ViamAPI() {\n" +
+		"    this.privateKey = \"\";\n" +
 		"    this.config = {\n" +
 		"        headers: {\n" +
 		"            'publicKey': '',\n" +
 		"            'uuid': '',\n" +
 		"            'deviceHash': '',\n" +
-		"            'token': ''\n" +
+		"            'token': '',\n" +
+		"            'nonce': '',\n" +
+		"            'nonceSignature': ''\n" +
 		"        }\n" +
 		"    }\n" +
 		"}\n\n"
@@ -99,10 +102,24 @@ func buildViamAPI() string {
 		"    this.config.headers.publicKey = window.btoa(authenticationPublicKey);\n" +
 		"};\n\n"
 
-	result += "ViamAPI.prototype.getConfig = function() {\n" +
-		"    return this.config;\n" +
+	result += "ViamAPI.prototype.setNonceSignature = function(nonceSignature) {\n" +
+		"    this.config.headers.nonceSignature = nonceSignature;\n" +
 		"};\n\n"
 
+    result += "ViamAPI.prototype.setNonce = function(nonce) {\n" +
+            "    this.config.headers.nonce = nonce;\n" +
+            "};\n\n"
+    result += "ViamAPI.prototype.getNonce = function() {\n" +
+                "    return this.config.headers.nonce;\n" +
+                "};\n\n"
+	result += "ViamAPI.prototype.setPrivateKey = function(privateKey) {\n" +
+		"    this.privateKey = privateKey;\n" +
+		"};\n\n"
+
+    result += "ViamAPI.prototype.getConfig = function() {\n" +
+            "    return this.config;\n" +
+            "};\n\n"
+
 	for i := 0; i < keysLen; i++ {
 		url := keys[i]
 		if endPoints[url].Form != nil {