diff --git a/src/account.h b/src/account.h
index 3200da86d1e48fd37c199643b8be8ec1347c7852..80515e47bafb8ae26c6677c23481c1b6d87e976b 100644
--- a/src/account.h
+++ b/src/account.h
@@ -52,6 +52,12 @@ namespace Json {
 class Value;
 }
 
+namespace dht {
+namespace crypto {
+struct Certificate;
+}
+}
+
 namespace jami {
 static constexpr uint64_t JAMI_ID_MAX_VAL = 9007199254740992;
 constexpr static const char RINGDIR[] = "ringtones";
@@ -343,7 +349,8 @@ public:
      */
     virtual void connectivityChanged() {};
 
-    virtual bool handleMessage(const std::string& /*from*/,
+    virtual bool handleMessage(const std::shared_ptr<dht::crypto::Certificate>& /*cert*/,
+                               const std::string& /*from*/,
                                const std::pair<std::string, std::string>& /*message*/)
     {
         return false;
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 56727a670317e9de4664baf2d77885fdfa6579fe..3ee4196a08f6a50546c253485e0227f4f52f9f96 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -2387,12 +2387,12 @@ JamiAccount::syncModule()
 void
 JamiAccount::onTextMessage(const std::string& id,
                            const std::string& from,
-                           const std::string& deviceId,
+                           const std::shared_ptr<dht::crypto::Certificate>& peerCert,
                            const std::map<std::string, std::string>& payloads)
 {
     try {
         const std::string fromUri {parseJamiUri(from)};
-        SIPAccountBase::onTextMessage(id, fromUri, deviceId, payloads);
+        SIPAccountBase::onTextMessage(id, fromUri, peerCert, payloads);
     } catch (...) {
     }
 }
@@ -3569,19 +3569,29 @@ JamiAccount::sendInstantMessage(const std::string& convId,
 }
 
 bool
-JamiAccount::handleMessage(const std::string& from, const std::pair<std::string, std::string>& m)
+JamiAccount::handleMessage(const std::shared_ptr<dht::crypto::Certificate>& cert, const std::string& from, const std::pair<std::string, std::string>& m)
 {
+    if (not cert or not cert->issuer)
+        return true; // stop processing message
+
+    if (cert->issuer->getId().to_view() != from) {
+        JAMI_WARNING("[Account {}] [device {}] handleMessage: invalid author {}", getAccountID(), cert->issuer->getId().to_view(), from);
+        return true;
+    }
     if (m.first == MIME_TYPE_GIT) {
         Json::Value json;
         if (!json::parse(m.second, json)) {
-            return false;
+            return true;
         }
 
-        std::string deviceId = json["deviceId"].asString();
-        std::string id = json["id"].asString();
-        std::string commit = json["commit"].asString();
         // fetchNewCommits will do heavy stuff like fetching, avoid to block SIP socket
-        dht::ThreadPool::io().run([w = weak(), from, deviceId, id, commit] {
+        dht::ThreadPool::io().run([
+            w = weak(),
+            from,
+            deviceId = json["deviceId"].asString(),
+            id = json["id"].asString(),
+            commit = json["commit"].asString()
+        ] {
             if (auto shared = w.lock()) {
                 if (auto cm = shared->convModule())
                     cm->fetchNewCommits(from, deviceId, id, commit);
@@ -3594,7 +3604,7 @@ JamiAccount::handleMessage(const std::string& from, const std::pair<std::string,
     } else if (m.first == MIME_TYPE_INVITE_JSON) {
         Json::Value json;
         if (!json::parse(m.second, json)) {
-            return false;
+            return true;
         }
         convModule()->onConversationRequest(from, json);
         return true;
@@ -3638,7 +3648,7 @@ JamiAccount::handleMessage(const std::string& from, const std::pair<std::string,
                 messageId = matched_pattern[1];
             } else {
                 JAMI_WARNING("Message displayed: unable to parse message ID");
-                return false;
+                return true;
             }
 
             static const std::regex STATUS_REGEX("<status>\\s*<(\\w+)\\/>\\s*<\\/status>");
@@ -3648,7 +3658,7 @@ JamiAccount::handleMessage(const std::string& from, const std::pair<std::string,
                 isDisplayed = matched_pattern[1] == "displayed";
             } else {
                 JAMI_WARNING("Message displayed: unable to parse status");
-                return false;
+                return true;
             }
 
             static const std::regex CONVID_REGEX("<conversation>\\s*(\\w+)\\s*<\\/conversation>");
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index dec8ec3e836445cf5ce479cded97e943f5d898f5..1ba574d1d751f84ea748731ef77a673ca305b158 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -261,7 +261,7 @@ public:
 
     void onTextMessage(const std::string& id,
                        const std::string& from,
-                       const std::string& deviceId,
+                       const std::shared_ptr<dht::crypto::Certificate>& peerCert,
                        const std::map<std::string, std::string>& payloads) override;
     void loadConversation(const std::string& convId);
 
@@ -468,7 +468,8 @@ public:
 
     // Received a new commit notification
 
-    bool handleMessage(const std::string& from,
+    bool handleMessage(const std::shared_ptr<dht::crypto::Certificate>& cert,
+                       const std::string& from,
                        const std::pair<std::string, std::string>& message) override;
 
     void monitor();
diff --git a/src/jamidht/message_channel_handler.cpp b/src/jamidht/message_channel_handler.cpp
index 97046eaae7356a21f319292ab05bb8152326719f..ca0e892b15fc222ff7a2ebccbe143b138d1c90ca 100644
--- a/src/jamidht/message_channel_handler.cpp
+++ b/src/jamidht/message_channel_handler.cpp
@@ -145,7 +145,7 @@ MessageChannelHandler::onReady(const std::shared_ptr<dht::crypto::Certificate>&
 
     socket->setOnRecv([acc = pimpl_->account_.lock(),
                        peerId,
-                       deviceId = device.toString(),
+                       cert,
                        ctx = std::make_shared<DecodingContext>()](const uint8_t* buf, size_t len) {
         if (!buf || !acc)
             return len;
@@ -159,10 +159,10 @@ MessageChannelHandler::onReady(const std::shared_ptr<dht::crypto::Certificate>&
             while (ctx->pac.next(oh)) {
                 Message msg;
                 oh.get().convert(msg);
-                acc->onTextMessage("", peerId, deviceId, {{msg.t, msg.c}});
+                acc->onTextMessage("", peerId, cert, {{msg.t, msg.c}});
             }
         } catch (const std::exception& e) {
-            JAMI_WARNING("[convInfo] Error parsing message: {:s}", e.what());
+            JAMI_WARNING("[convInfo] error on sync: {:s}", e.what());
         }
         return len;
     });
diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp
index 630190a961c9a03defdde3f7346b6f30d80a9846..5d594450e0874ed38f4568c5259fa417d354eb0c 100644
--- a/src/sip/sipaccountbase.cpp
+++ b/src/sip/sipaccountbase.cpp
@@ -274,10 +274,10 @@ SIPAccountBase::getIceOptions() const noexcept
 void
 SIPAccountBase::onTextMessage(const std::string& id,
                               const std::string& from,
-                              const std::string& /* deviceId */,
+                              const std::shared_ptr<dht::crypto::Certificate>& peerCert,
                               const std::map<std::string, std::string>& payloads)
 {
-    JAMI_LOG("[Account {}] Text message received from {}, {:d} part(s)", accountID_, from, payloads.size());
+    JAMI_LOG("[Account {}] [peer {}] Text message received from {}, {:d} part(s)", accountID_, peerCert ? peerCert->getLongId().to_view() : ""sv, from, payloads.size());
     for (const auto& m : payloads) {
         if (!utf8_validate(m.first))
             return;
@@ -285,7 +285,7 @@ SIPAccountBase::onTextMessage(const std::string& id,
             JAMI_WARNING("[Account {}] Dropping invalid message with MIME type {}", accountID_, m.first);
             return;
         }
-        if (handleMessage(from, m))
+        if (handleMessage(peerCert, from, m))
             return;
     }
 
diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h
index eee50e845df648b98edd30bb292d2fe611678c9f..8c2aa14d2be9c2a4bb91eafc8eaf2f8187adcc28 100644
--- a/src/sip/sipaccountbase.h
+++ b/src/sip/sipaccountbase.h
@@ -201,7 +201,7 @@ public:
 
     virtual void onTextMessage(const std::string& id,
                                const std::string& from,
-                               const std::string& deviceId,
+                               const std::shared_ptr<dht::crypto::Certificate>& peerCert,
                                const std::map<std::string, std::string>& payloads);
 
     /* Returns true if the username and/or hostname match this account */
diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp
index b159fe634b9208e7791d13eba1fec85930fb4f8b..f13e6337605ae2a46823c86f102f47a6450e9351 100644
--- a/src/sip/sipvoiplink.cpp
+++ b/src/sip/sipvoiplink.cpp
@@ -348,7 +348,7 @@ transaction_request_cb(pjsip_rx_data* rdata)
                     } catch (...) {
                     }
                 }
-                account->onTextMessage(id, peerNumber, std::string(transport->deviceId()), payloads);
+                account->onTextMessage(id, peerNumber, transport->getTlsInfos().peerCert, payloads);
             }
             return PJ_FALSE;
         }