diff --git a/src/jamidht/account_manager.h b/src/jamidht/account_manager.h
index bd3f8490998a8c926ec2ff7c3b9de0f742eac70b..dfe97618e45993f5eb187af665a0aee7428250da 100644
--- a/src/jamidht/account_manager.h
+++ b/src/jamidht/account_manager.h
@@ -67,20 +67,17 @@ dynamic_unique_cast(std::unique_ptr<From>&& p)
     return {};
 }
 
-class AccountManager
+class AccountManager: public std::enable_shared_from_this<AccountManager>
 {
 public:
-    using AsyncUser = std::function<void(AccountManager&)>;
-    using OnAsync = std::function<void(AsyncUser&&)>;
     using OnChangeCallback = ContactList::OnChangeCallback;
     using clock = std::chrono::system_clock;
     using time_point = clock::time_point;
     using OnNewDeviceCb = std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>;
     using OnDeviceAnnouncedCb = std::function<void()>;
 
-    AccountManager(const std::string& path, OnAsync&& onAsync, const std::string& nameServer)
+    AccountManager(const std::string& path, const std::string& nameServer)
         : path_(path)
-        , onAsync_(std::move(onAsync))
         , nameDir_(NameDirectory::instance(nameServer)) {};
 
     virtual ~AccountManager();
@@ -269,7 +266,6 @@ public:
 
 protected:
     std::string path_;
-    OnAsync onAsync_;
     OnChangeCallback onChange_;
     std::unique_ptr<AccountInfo> info_;
     std::shared_ptr<dht::DhtRunner> dht_;
diff --git a/src/jamidht/archive_account_manager.cpp b/src/jamidht/archive_account_manager.cpp
index 9b887bb4bec4b43d235975ee3a90e72ec9ec6696..63fa1e11b1bbb864823fc6455c12a6a3c2595314 100644
--- a/src/jamidht/archive_account_manager.cpp
+++ b/src/jamidht/archive_account_manager.cpp
@@ -66,53 +66,52 @@ ArchiveAccountManager::initAuthentication(const std::string& accountId,
         return;
     }
 
-    dht::ThreadPool::computation().run([ctx = std::move(ctx), onAsync = onAsync_]() mutable {
-        onAsync([ctx = std::move(ctx)](AccountManager& accountManager) mutable {
-            auto& this_ = *static_cast<ArchiveAccountManager*>(&accountManager);
-            try {
-                if (ctx->credentials->scheme == "file") {
-                    // Import from external archive
-                    this_.loadFromFile(*ctx);
-                } else {
-                    // Create/migrate local account
-                    bool hasArchive = not ctx->credentials->uri.empty()
-                                      and fileutils::isFile(ctx->credentials->uri);
-                    if (hasArchive) {
-                        // Create/migrate from local archive
-                        if (ctx->credentials->updateIdentity.first
-                            and ctx->credentials->updateIdentity.second
-                            and needsMigration(ctx->credentials->updateIdentity)) {
-                            this_.migrateAccount(*ctx);
-                        } else {
-                            this_.loadFromFile(*ctx);
-                        }
-                    } else if (ctx->credentials->updateIdentity.first
-                               and ctx->credentials->updateIdentity.second) {
-                        auto future_keypair = dht::ThreadPool::computation().get<dev::KeyPair>(
-                            &dev::KeyPair::create);
-                        AccountArchive a;
-                        JAMI_WARN("[Auth] converting certificate from old account %s",
-                                  ctx->credentials->updateIdentity.first->getPublicKey()
-                                      .getId()
-                                      .toString()
-                                      .c_str());
-                        a.id = std::move(ctx->credentials->updateIdentity);
-                        try {
-                            a.ca_key = std::make_shared<dht::crypto::PrivateKey>(
-                                fileutils::loadFile("ca.key", this_.path_));
-                        } catch (...) {
-                        }
-                        this_.updateCertificates(a, ctx->credentials->updateIdentity);
-                        a.eth_key = future_keypair.get().secret().makeInsecure().asBytes();
-                        this_.onArchiveLoaded(*ctx, std::move(a));
+    dht::ThreadPool::computation().run([ctx = std::move(ctx), w = weak_from_this()] mutable {
+        auto this_ = std::static_pointer_cast<ArchiveAccountManager>(w.lock());
+        if (not this_) return;
+        try {
+            if (ctx->credentials->scheme == "file") {
+                // Import from external archive
+                this_->loadFromFile(*ctx);
+            } else {
+                // Create/migrate local account
+                bool hasArchive = not ctx->credentials->uri.empty()
+                                    and fileutils::isFile(ctx->credentials->uri);
+                if (hasArchive) {
+                    // Create/migrate from local archive
+                    if (ctx->credentials->updateIdentity.first
+                        and ctx->credentials->updateIdentity.second
+                        and needsMigration(ctx->credentials->updateIdentity)) {
+                        this_->migrateAccount(*ctx);
                     } else {
-                        this_.createAccount(*ctx);
+                        this_->loadFromFile(*ctx);
+                    }
+                } else if (ctx->credentials->updateIdentity.first
+                            and ctx->credentials->updateIdentity.second) {
+                    auto future_keypair = dht::ThreadPool::computation().get<dev::KeyPair>(
+                        &dev::KeyPair::create);
+                    AccountArchive a;
+                    JAMI_WARN("[Auth] converting certificate from old account %s",
+                                ctx->credentials->updateIdentity.first->getPublicKey()
+                                    .getId()
+                                    .toString()
+                                    .c_str());
+                    a.id = std::move(ctx->credentials->updateIdentity);
+                    try {
+                        a.ca_key = std::make_shared<dht::crypto::PrivateKey>(
+                            fileutils::loadFile("ca.key", this_->path_));
+                    } catch (...) {
                     }
+                    this_->updateCertificates(a, ctx->credentials->updateIdentity);
+                    a.eth_key = future_keypair.get().secret().makeInsecure().asBytes();
+                    this_->onArchiveLoaded(*ctx, std::move(a));
+                } else {
+                    this_->createAccount(*ctx);
                 }
-            } catch (const std::exception& e) {
-                ctx->onFailure(AuthError::UNKNOWN, e.what());
             }
-        });
+        } catch (const std::exception& e) {
+            ctx->onFailure(AuthError::UNKNOWN, e.what());
+        }
     });
 }
 
@@ -283,7 +282,7 @@ ArchiveAccountManager::loadFromDHT(const std::shared_ptr<AuthContext>& ctx)
         }
     };
 
-    auto search = [ctx, searchEnded, onAsync = onAsync_](bool previous) {
+    auto search = [ctx, searchEnded, w=weak_from_this()](bool previous) {
         std::vector<uint8_t> key;
         dht::InfoHash loc;
         auto& s = previous ? ctx->dhtContext->stateOld : ctx->dhtContext->stateNew;
@@ -301,7 +300,7 @@ ArchiveAccountManager::loadFromDHT(const std::shared_ptr<AuthContext>& ctx)
             }
             ctx->dhtContext->dht.get(
                 loc,
-                [ctx, key = std::move(key), onAsync](const std::shared_ptr<dht::Value>& val) {
+                [ctx, key = std::move(key), w](const std::shared_ptr<dht::Value>& val) {
                     std::vector<uint8_t> decrypted;
                     try {
                         decrypted = archiver::decompress(dht::crypto::aesDecrypt(val->data, key));
@@ -311,19 +310,17 @@ ArchiveAccountManager::loadFromDHT(const std::shared_ptr<AuthContext>& ctx)
                     JAMI_DBG("[Auth] found archive on the DHT");
                     ctx->dhtContext->found = true;
                     dht::ThreadPool::computation().run([ctx,
-                                                        decrypted = std::move(decrypted),
-                                                        onAsync] {
+                                                        decrypted = std::move(decrypted), w] {
                         try {
                             auto archive = AccountArchive(decrypted);
-                            onAsync([&](AccountManager& accountManager) {
-                                auto& this_ = *static_cast<ArchiveAccountManager*>(&accountManager);
+                            if (auto sthis = std::static_pointer_cast<ArchiveAccountManager>(w.lock())) {
                                 if (ctx->dhtContext) {
                                     ctx->dhtContext->dht.join();
                                     ctx->dhtContext.reset();
                                 }
-                                this_.onArchiveLoaded(*ctx,
+                                sthis->onArchiveLoaded(*ctx,
                                                       std::move(archive) /*, std::move(contacts)*/);
-                            });
+                            }
                         } catch (const std::exception& e) {
                             ctx->onFailure(AuthError::UNKNOWN, "");
                         }
@@ -671,53 +668,51 @@ generatePIN(size_t length = 16, size_t split = 8)
 void
 ArchiveAccountManager::addDevice(const std::string& password, AddDeviceCallback cb)
 {
-    dht::ThreadPool::computation().run([onAsync = onAsync_, password, cb = std::move(cb)]() mutable {
-        onAsync([password = std::move(password),
-                 cb = std::move(cb)](AccountManager& accountManager) mutable {
-            auto& this_ = *static_cast<ArchiveAccountManager*>(&accountManager);
-
-            std::vector<uint8_t> key;
-            dht::InfoHash loc;
-            std::string pin_str;
-            AccountArchive a;
-            try {
-                JAMI_DBG("[Auth] exporting account");
+    dht::ThreadPool::computation().run([password, cb = std::move(cb), w=weak_from_this()] mutable {
+        auto this_ = std::static_pointer_cast<ArchiveAccountManager>(w.lock());
+        if (not this_) return;
 
-                a = this_.readArchive(password);
+        std::vector<uint8_t> key;
+        dht::InfoHash loc;
+        std::string pin_str;
+        AccountArchive a;
+        try {
+            JAMI_DBG("[Auth] exporting account");
 
-                // Generate random PIN
-                pin_str = generatePIN();
+            a = this_->readArchive(password);
 
-                std::tie(key, loc) = computeKeys(password, pin_str);
-            } catch (const std::exception& e) {
-                JAMI_ERR("[Auth] can't export account: %s", e.what());
-                cb(AddDeviceResult::ERROR_CREDENTIALS, {});
-                return;
-            }
-            // now that key and loc are computed, display to user in lowercase
-            std::transform(pin_str.begin(), pin_str.end(), pin_str.begin(), ::tolower);
-            try {
-                this_.updateArchive(a);
-                auto encrypted = dht::crypto::aesEncrypt(archiver::compress(a.serialize()), key);
-                if (not this_.dht_ or not this_.dht_->isRunning())
-                    throw std::runtime_error("DHT is not running..");
-                JAMI_WARN("[Auth] exporting account with PIN: %s at %s (size %zu)",
-                          pin_str.c_str(),
-                          loc.toString().c_str(),
-                          encrypted.size());
-                this_.dht_->put(loc, encrypted, [cb, pin = std::move(pin_str)](bool ok) {
-                    JAMI_DBG("[Auth] account archive published: %s", ok ? "success" : "failure");
-                    if (ok)
-                        cb(AddDeviceResult::SUCCESS_SHOW_PIN, pin);
-                    else
-                        cb(AddDeviceResult::ERROR_NETWORK, {});
-                });
-            } catch (const std::exception& e) {
-                JAMI_ERR("[Auth] can't export account: %s", e.what());
-                cb(AddDeviceResult::ERROR_NETWORK, {});
-                return;
-            }
-        });
+            // Generate random PIN
+            pin_str = generatePIN();
+
+            std::tie(key, loc) = computeKeys(password, pin_str);
+        } catch (const std::exception& e) {
+            JAMI_ERR("[Auth] can't export account: %s", e.what());
+            cb(AddDeviceResult::ERROR_CREDENTIALS, {});
+            return;
+        }
+        // now that key and loc are computed, display to user in lowercase
+        std::transform(pin_str.begin(), pin_str.end(), pin_str.begin(), ::tolower);
+        try {
+            this_->updateArchive(a);
+            auto encrypted = dht::crypto::aesEncrypt(archiver::compress(a.serialize()), key);
+            if (not this_->dht_ or not this_->dht_->isRunning())
+                throw std::runtime_error("DHT is not running..");
+            JAMI_WARN("[Auth] exporting account with PIN: %s at %s (size %zu)",
+                        pin_str.c_str(),
+                        loc.toString().c_str(),
+                        encrypted.size());
+            this_->dht_->put(loc, encrypted, [cb, pin = std::move(pin_str)](bool ok) {
+                JAMI_DBG("[Auth] account archive published: %s", ok ? "success" : "failure");
+                if (ok)
+                    cb(AddDeviceResult::SUCCESS_SHOW_PIN, pin);
+                else
+                    cb(AddDeviceResult::ERROR_NETWORK, {});
+            });
+        } catch (const std::exception& e) {
+            JAMI_ERR("[Auth] can't export account: %s", e.what());
+            cb(AddDeviceResult::ERROR_NETWORK, {});
+            return;
+        }
     });
 }
 
@@ -730,45 +725,40 @@ ArchiveAccountManager::revokeDevice(
     auto fa = dht::ThreadPool::computation().getShared<AccountArchive>(
         [this, password] { return readArchive(password); });
     findCertificate(DeviceId(device),
-                    [fa = std::move(fa), password, device, cb, onAsync = onAsync_](
-                        const std::shared_ptr<dht::crypto::Certificate>& crt) mutable {
-                        if (not crt) {
-                            cb(RevokeDeviceResult::ERROR_NETWORK);
-                            return;
-                        }
-                        onAsync([cb,
-                                 crt = std::move(crt),
-                                 fa = std::move(fa),
-                                 password = std::move(password)](
-                                    AccountManager& accountManager) mutable {
-                            auto& this_ = *static_cast<ArchiveAccountManager*>(&accountManager);
-                            this_.info_->contacts->foundAccountDevice(crt);
-                            AccountArchive a;
-                            try {
-                                a = fa.get();
-                            } catch (...) {
-                                cb(RevokeDeviceResult::ERROR_CREDENTIALS);
-                                return;
-                            }
-                            // Add revoked device to the revocation list and resign it
-                            if (not a.revoked)
-                                a.revoked = std::make_shared<decltype(a.revoked)::element_type>();
-                            a.revoked->revoke(*crt);
-                            a.revoked->sign(a.id);
-                            // add to CRL cache
-                            this_.certStore().pinRevocationList(a.id.second->getId().toString(), a.revoked);
-                            this_.certStore().loadRevocations(*a.id.second);
-
-                            // Announce CRL immediately
-                            auto h = a.id.second->getId();
-                            this_.dht_->put(h, a.revoked, dht::DoneCallback {}, {}, true);
-
-                            this_.saveArchive(a, password);
-                            this_.info_->contacts->removeAccountDevice(crt->getLongId());
-                            cb(RevokeDeviceResult::SUCCESS);
-                            this_.syncDevices();
-                        });
-                    });
+        [fa = std::move(fa), password, device, cb, w=weak_from_this()](
+            const std::shared_ptr<dht::crypto::Certificate>& crt) mutable {
+                if (not crt) {
+                    cb(RevokeDeviceResult::ERROR_NETWORK);
+                    return;
+                }
+                auto this_ = std::static_pointer_cast<ArchiveAccountManager>(w.lock());
+                if (not this_) return;
+                this_->info_->contacts->foundAccountDevice(crt);
+                AccountArchive a;
+                try {
+                    a = fa.get();
+                } catch (...) {
+                    cb(RevokeDeviceResult::ERROR_CREDENTIALS);
+                    return;
+                }
+                // Add revoked device to the revocation list and resign it
+                if (not a.revoked)
+                    a.revoked = std::make_shared<decltype(a.revoked)::element_type>();
+                a.revoked->revoke(*crt);
+                a.revoked->sign(a.id);
+                // add to CRL cache
+                this_->certStore().pinRevocationList(a.id.second->getId().toString(), a.revoked);
+                this_->certStore().loadRevocations(*a.id.second);
+
+                // Announce CRL immediately
+                auto h = a.id.second->getId();
+                this_->dht_->put(h, a.revoked, dht::DoneCallback {}, {}, true);
+
+                this_->saveArchive(a, password);
+                this_->info_->contacts->removeAccountDevice(crt->getLongId());
+                cb(RevokeDeviceResult::SUCCESS);
+                this_->syncDevices();
+            });
     return false;
 }
 
diff --git a/src/jamidht/archive_account_manager.h b/src/jamidht/archive_account_manager.h
index 5d1181f3f465b6cbd657f51c3575e699955a39c9..dfd5ae4a38e683736f9ac2442dc284a014938a7e 100644
--- a/src/jamidht/archive_account_manager.h
+++ b/src/jamidht/archive_account_manager.h
@@ -27,11 +27,10 @@ public:
     using OnExportConfig = std::function<std::map<std::string, std::string>()>;
 
     ArchiveAccountManager(const std::string& path,
-                          OnAsync&& onAsync,
                           OnExportConfig&& onExportConfig,
                           std::string archivePath,
                           const std::string& nameServer)
-        : AccountManager(path, std::move(onAsync), nameServer)
+        : AccountManager(path, nameServer)
         , onExportConfig_(std::move(onExportConfig))
         , archivePath_(std::move(archivePath)) {}
 
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 0fe2858d4bba820cf850c4efcfcf0cbe95e5bc7a..d1f7527d5143df7f201fd809a38982cedefcb565 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -269,11 +269,11 @@ dhtStatusStr(dht::NodeStatus status)
 
 JamiAccount::JamiAccount(const std::string& accountId)
     : SIPAccountBase(accountId)
-    , certStore_ {std::make_unique<dhtnet::tls::CertificateStore>(idPath_, Logger::dhtLogger())}
-    , dht_(new dht::DhtRunner)
     , idPath_(fileutils::get_data_dir() + DIR_SEPARATOR_STR + accountId)
     , cachePath_(fileutils::get_cache_dir() + DIR_SEPARATOR_STR + accountId)
     , dataPath_(cachePath_ + DIR_SEPARATOR_STR "values")
+    , certStore_ {std::make_unique<dhtnet::tls::CertificateStore>(idPath_, Logger::dhtLogger())}
+    , dht_(new dht::DhtRunner)
     , connectionManager_ {}
     , nonSwarmTransferManager_(std::make_shared<TransferManager>(accountId, ""))
 {}
@@ -1177,20 +1177,14 @@ JamiAccount::loadAccount(const std::string& archive_password,
 
     const auto& conf = config();
     try {
-        auto onAsync = [w = weak()](AccountManager::AsyncUser&& cb) {
-            if (auto this_ = w.lock())
-                cb(*this_->accountManager_);
-        };
         if (conf.managerUri.empty()) {
-            accountManager_.reset(new ArchiveAccountManager(
+            accountManager_ = std::make_shared<ArchiveAccountManager>(
                 getPath(),
-                onAsync,
                 [this]() { return getAccountDetails(); },
                 conf.archivePath.empty() ? "archive.gz" : conf.archivePath,
-                conf.nameServer));
+                conf.nameServer);
         } else {
-            accountManager_.reset(
-                new ServerAccountManager(getPath(), onAsync, conf.managerUri, conf.nameServer));
+            accountManager_ = std::make_shared<ServerAccountManager>(getPath(), conf.managerUri, conf.nameServer);
         }
 
         auto id = accountManager_->loadIdentity(getAccountID(),
@@ -1265,10 +1259,12 @@ JamiAccount::loadAccount(const std::string& archive_password,
                 fDeviceKey,
                 ip_utils::getDeviceName(),
                 std::move(creds),
-                [this, migrating, hasPassword](const AccountInfo& info,
+                [w=weak(), this, migrating, hasPassword](const AccountInfo& info,
                                                const std::map<std::string, std::string>& config,
                                                std::string&& receipt,
                                                std::vector<uint8_t>&& receipt_signature) {
+                    auto sthis = w.lock();
+                    if (not sthis) return;
                     JAMI_LOG("[Account {}] Auth success!", getAccountID());
 
                     fileutils::check_dir(idPath_.c_str(), 0700);
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index dc85f4527977ae120dd52927798b4080439fc12a..919af7d415f4780e3faf5ec46b232872ce5da265 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -698,6 +698,10 @@ private:
     void newSwarmOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, const Uri& uri);
     std::shared_ptr<SIPCall> createSubCall(const std::shared_ptr<SIPCall>& mainCall);
 
+    std::string idPath_ {};
+    std::string cachePath_ {};
+    std::string dataPath_ {};
+
 #if HAVE_RINGNS
     std::string registeredName_;
 #endif
@@ -705,16 +709,13 @@ private:
     std::unique_ptr<dhtnet::tls::CertificateStore> certStore_;
 
     std::shared_ptr<dht::DhtRunner> dht_ {};
-    std::unique_ptr<AccountManager> accountManager_;
+    std::shared_ptr<AccountManager> accountManager_;
     dht::crypto::Identity id_ {};
 
     mutable std::mutex messageMutex_ {};
     std::map<dht::Value::Id, PendingMessage> sentMessages_;
     std::set<std::string, std::less<>> treatedMessages_ {};
 
-    std::string idPath_ {};
-    std::string cachePath_ {};
-    std::string dataPath_ {};
 
     /* tracked buddies presence */
     mutable std::mutex buddyInfoMtx;
diff --git a/src/jamidht/server_account_manager.cpp b/src/jamidht/server_account_manager.cpp
index 03ed1e029337f906c19454d8a076bf8822051fb7..e1b57f5ec3727f6b68a71810e659999146eb8f69 100644
--- a/src/jamidht/server_account_manager.cpp
+++ b/src/jamidht/server_account_manager.cpp
@@ -43,10 +43,9 @@ constexpr std::string_view PATH_SEARCH = JAMI_PATH_AUTH "/directory/search";
 constexpr std::string_view PATH_CONTACTS = JAMI_PATH_AUTH "/contacts";
 
 ServerAccountManager::ServerAccountManager(const std::string& path,
-                                           OnAsync&& onAsync,
                                            const std::string& managerHostname,
                                            const std::string& nameServer)
-    : AccountManager(path, std::move(onAsync), nameServer)
+    : AccountManager(path, nameServer)
     , managerHostname_(managerHostname)
     , logger_(Logger::dhtLogger()) {}
 
@@ -84,131 +83,125 @@ ServerAccountManager::initAuthentication(const std::string& accountId,
               ctx->credentials->username.c_str(),
               url.c_str());
 
-    dht::ThreadPool::computation().run([onAsync = onAsync_, ctx, url] {
-        onAsync([=](AccountManager& accountManager) {
-            auto& this_ = *static_cast<ServerAccountManager*>(&accountManager);
-            Json::Value body;
-            {
-                auto csr = ctx->request.get()->toString();
-                body["csr"] = csr;
-                body["deviceName"] = ctx->deviceName;
-            }
-            auto request = std::make_shared<Request>(
-                *Manager::instance().ioContext(),
-                url,
-                body,
-                [ctx, onAsync](Json::Value json, const dht::http::Response& response) {
-                    JAMI_DBG("[Auth] Got request callback with status code=%u",
-                             response.status_code);
-                    if (response.status_code == 0)
-                        ctx->onFailure(AuthError::SERVER_ERROR, "Can't connect to server");
-                    else if (response.status_code >= 400 && response.status_code < 500)
-                        ctx->onFailure(AuthError::INVALID_ARGUMENTS, "");
-                    else if (response.status_code < 200 || response.status_code > 299)
-                        ctx->onFailure(AuthError::INVALID_ARGUMENTS, "");
-                    else {
-                        do {
-                            try {
-                                JAMI_WARNING("[Auth] Got server response: {}", response.body);
-                                auto cert = std::make_shared<dht::crypto::Certificate>(
-                                    json["certificateChain"].asString());
-                                auto accountCert = cert->issuer;
-                                if (not accountCert) {
-                                    JAMI_ERR("[Auth] Can't parse certificate: no issuer");
-                                    ctx->onFailure(AuthError::SERVER_ERROR,
-                                                   "Invalid certificate from server");
-                                    break;
-                                }
-                                auto receipt = json["deviceReceipt"].asString();
-                                Json::Value receiptJson;
-                                std::string err;
-                                auto receiptReader = std::unique_ptr<Json::CharReader>(
-                                    Json::CharReaderBuilder {}.newCharReader());
-                                if (!receiptReader->parse(receipt.data(),
-                                                          receipt.data() + receipt.size(),
-                                                          &receiptJson,
-                                                          &err)) {
-                                    JAMI_ERR("[Auth] Can't parse receipt from server: %s",
-                                             err.c_str());
-                                    ctx->onFailure(AuthError::SERVER_ERROR,
-                                                   "Can't parse receipt from server");
-                                    break;
+    dht::ThreadPool::computation().run([ctx, url, w=weak_from_this()] {
+        auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock());
+        if (not this_) return;
+        Json::Value body;
+        {
+            auto csr = ctx->request.get()->toString();
+            body["csr"] = csr;
+            body["deviceName"] = ctx->deviceName;
+        }
+        auto request = std::make_shared<Request>(
+            *Manager::instance().ioContext(),
+            url,
+            body,
+            [ctx, w](Json::Value json, const dht::http::Response& response) {
+                JAMI_DBG("[Auth] Got request callback with status code=%u",
+                            response.status_code);
+                auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock());
+                if (response.status_code == 0 || this_ == nullptr)
+                    ctx->onFailure(AuthError::SERVER_ERROR, "Can't connect to server");
+                else if (response.status_code >= 400 && response.status_code < 500)
+                    ctx->onFailure(AuthError::INVALID_ARGUMENTS, "");
+                else if (response.status_code < 200 || response.status_code > 299)
+                    ctx->onFailure(AuthError::INVALID_ARGUMENTS, "");
+                else {
+                    do {
+                        try {
+                            JAMI_WARNING("[Auth] Got server response: {}", response.body);
+                            auto cert = std::make_shared<dht::crypto::Certificate>(
+                                json["certificateChain"].asString());
+                            auto accountCert = cert->issuer;
+                            if (not accountCert) {
+                                JAMI_ERR("[Auth] Can't parse certificate: no issuer");
+                                ctx->onFailure(AuthError::SERVER_ERROR,
+                                                "Invalid certificate from server");
+                                break;
+                            }
+                            auto receipt = json["deviceReceipt"].asString();
+                            Json::Value receiptJson;
+                            std::string err;
+                            auto receiptReader = std::unique_ptr<Json::CharReader>(
+                                Json::CharReaderBuilder {}.newCharReader());
+                            if (!receiptReader->parse(receipt.data(),
+                                                        receipt.data() + receipt.size(),
+                                                        &receiptJson,
+                                                        &err)) {
+                                JAMI_ERR("[Auth] Can't parse receipt from server: %s",
+                                            err.c_str());
+                                ctx->onFailure(AuthError::SERVER_ERROR,
+                                                "Can't parse receipt from server");
+                                break;
+                            }
+                            auto receiptSignature = base64::decode(
+                                json["receiptSignature"].asString());
+
+                            auto info = std::make_unique<AccountInfo>();
+                            info->identity.first = ctx->key.get();
+                            info->identity.second = cert;
+                            info->devicePk = cert->getSharedPublicKey();
+                            info->deviceId = info->devicePk->getLongId().toString();
+                            info->accountId = accountCert->getId().toString();
+                            info->contacts = std::make_unique<ContactList>(ctx->accountId,
+                                                                            accountCert,
+                                                                            this_->path_,
+                                                                            this_->onChange_);
+                            // info->contacts->setContacts(a.contacts);
+                            if (ctx->deviceName.empty())
+                                ctx->deviceName = info->deviceId.substr(8);
+                            info->contacts->foundAccountDevice(cert,
+                                                                ctx->deviceName,
+                                                                clock::now());
+                            info->ethAccount = receiptJson["eth"].asString();
+                            info->announce
+                                = parseAnnounce(receiptJson["announce"].asString(),
+                                                info->accountId,
+                                                info->devicePk->getId().toString());
+                            if (not info->announce) {
+                                ctx->onFailure(AuthError::SERVER_ERROR,
+                                                "Can't parse announce from server");
+                                return;
+                            }
+                            info->username = ctx->credentials->username;
+
+                            this_->creds_ = std::move(ctx->credentials);
+                            this_->info_ = std::move(info);
+                            std::map<std::string, std::string> config;
+                            for (auto itr = json.begin(); itr != json.end(); ++itr) {
+                                const auto& name = itr.name();
+                                if (name == "nameServer"sv) {
+                                    auto nameServer = json["nameServer"].asString();
+                                    if (!nameServer.empty() && nameServer[0] == '/')
+                                        nameServer = this_->managerHostname_ + nameServer;
+                                    this_->nameDir_ = NameDirectory::instance(nameServer);
+                                    config
+                                        .emplace(libjami::Account::ConfProperties::RingNS::URI,
+                                                    std::move(nameServer));
+                                } else if (name == "userPhoto"sv) {
+                                    this_->info_->photo = json["userPhoto"].asString();
+                                } else {
+                                    config.emplace(name, itr->asString());
                                 }
-                                onAsync([=](AccountManager& accountManager) mutable {
-                                    auto& this_ = *static_cast<ServerAccountManager*>(
-                                        &accountManager);
-                                    auto receiptSignature = base64::decode(
-                                        json["receiptSignature"].asString());
-
-                                    auto info = std::make_unique<AccountInfo>();
-                                    info->identity.first = ctx->key.get();
-                                    info->identity.second = cert;
-                                    info->devicePk = cert->getSharedPublicKey();
-                                    info->deviceId = info->devicePk->getLongId().toString();
-                                    info->accountId = accountCert->getId().toString();
-                                    info->contacts = std::make_unique<ContactList>(ctx->accountId,
-                                                                                   accountCert,
-                                                                                   this_.path_,
-                                                                                   this_.onChange_);
-                                    // info->contacts->setContacts(a.contacts);
-                                    if (ctx->deviceName.empty())
-                                        ctx->deviceName = info->deviceId.substr(8);
-                                    info->contacts->foundAccountDevice(cert,
-                                                                       ctx->deviceName,
-                                                                       clock::now());
-                                    info->ethAccount = receiptJson["eth"].asString();
-                                    info->announce
-                                        = parseAnnounce(receiptJson["announce"].asString(),
-                                                        info->accountId,
-                                                        info->devicePk->getId().toString());
-                                    if (not info->announce) {
-                                        ctx->onFailure(AuthError::SERVER_ERROR,
-                                                       "Can't parse announce from server");
-                                        return;
-                                    }
-                                    info->username = ctx->credentials->username;
-
-                                    this_.creds_ = std::move(ctx->credentials);
-                                    this_.info_ = std::move(info);
-                                    std::map<std::string, std::string> config;
-                                    for (auto itr = json.begin(); itr != json.end(); ++itr) {
-                                        const auto& name = itr.name();
-                                        if (name == "nameServer"sv) {
-                                            auto nameServer = json["nameServer"].asString();
-                                            if (!nameServer.empty() && nameServer[0] == '/')
-                                                nameServer = this_.managerHostname_ + nameServer;
-                                            this_.nameDir_ = NameDirectory::instance(nameServer);
-                                            config
-                                                .emplace(libjami::Account::ConfProperties::RingNS::URI,
-                                                         std::move(nameServer));
-                                        } else if (name == "userPhoto"sv) {
-                                            this_.info_->photo = json["userPhoto"].asString();
-                                        } else {
-                                            config.emplace(name, itr->asString());
-                                        }
-                                    }
-
-                                    ctx->onSuccess(*this_.info_,
-                                                   std::move(config),
-                                                   std::move(receipt),
-                                                   std::move(receiptSignature));
-                                });
-                            } catch (const std::exception& e) {
-                                JAMI_ERR("Error when loading account: %s", e.what());
-                                ctx->onFailure(AuthError::NETWORK, "");
                             }
-                        } while (false);
-                    }
 
-                    onAsync([response](AccountManager& accountManager) {
-                        auto& this_ = *static_cast<ServerAccountManager*>(&accountManager);
-                        this_.clearRequest(response.request);
-                    });
-                },
-                this_.logger_);
-            request->set_auth(ctx->credentials->username, ctx->credentials->password);
-            this_.sendRequest(request);
-        });
+                            ctx->onSuccess(*this_->info_,
+                                            std::move(config),
+                                            std::move(receipt),
+                                            std::move(receiptSignature));
+                        } catch (const std::exception& e) {
+                            JAMI_ERR("Error when loading account: %s", e.what());
+                            ctx->onFailure(AuthError::NETWORK, "");
+                        }
+                    } while (false);
+                }
+
+                if (auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock()))
+                    this_->clearRequest(response.request);
+            },
+            this_->logger_);
+        request->set_auth(ctx->credentials->username, ctx->credentials->password);
+        this_->sendRequest(request);
     });
 }
 
@@ -244,11 +237,9 @@ ServerAccountManager::authenticateDevice()
         *Manager::instance().ioContext(),
         url,
         Json::Value {Json::objectValue},
-        [onAsync = onAsync_](Json::Value json, const dht::http::Response& response) {
-            onAsync([=](AccountManager& accountManager) {
-                static_cast<ServerAccountManager*>(&accountManager)
-                    ->onAuthEnded(json, response, TokenScope::Device);
-            });
+        [w=weak_from_this()](Json::Value json, const dht::http::Response& response) {
+            if (auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock()))
+                this_->onAuthEnded(json, response, TokenScope::Device);
         },
         logger_);
     request->set_identity(info_->identity);
@@ -265,11 +256,9 @@ ServerAccountManager::authenticateAccount(const std::string& username, const std
         *Manager::instance().ioContext(),
         url,
         Json::Value {Json::objectValue},
-        [onAsync = onAsync_](Json::Value json, const dht::http::Response& response) {
-            onAsync([=](AccountManager& accountManager) {
-                static_cast<ServerAccountManager*>(&accountManager)
-                    ->onAuthEnded(json, response, TokenScope::User);
-            });
+        [w=weak_from_this()](Json::Value json, const dht::http::Response& response) {
+            if (auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock()))
+                this_->onAuthEnded(json, response, TokenScope::User);
         },
         logger_);
     request->set_auth(username, password);
@@ -401,33 +390,32 @@ ServerAccountManager::syncDevices()
         *Manager::instance().ioContext(),
         urlContacts,
         jsonContacts,
-        [onAsync = onAsync_](Json::Value json, const dht::http::Response& response) {
-            onAsync([=](AccountManager& accountManager) {
+        [w=weak_from_this()](Json::Value json, const dht::http::Response& response) {
                 JAMI_DBG("[Auth] Got contact sync request callback with status code=%u",
                          response.status_code);
-                auto& this_ = *static_cast<ServerAccountManager*>(&accountManager);
-                if (response.status_code >= 200 && response.status_code < 300) {
-                    try {
-                        JAMI_WARN("[Auth] Got server response: %s", response.body.c_str());
-                        if (not json.isArray()) {
-                            JAMI_ERR("[Auth] Can't parse server response: not an array");
-                        } else {
-                            for (unsigned i = 0, n = json.size(); i < n; i++) {
-                                const auto& e = json[i];
-                                Contact contact(e);
-                                this_.info_->contacts
-                                    ->updateContact(dht::InfoHash {e["uri"].asString()}, contact);
-                            }
-                            this_.info_->contacts->saveContacts();
+            auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock());
+            if (!this_) return; 
+            if (response.status_code >= 200 && response.status_code < 300) {
+                try {
+                    JAMI_WARN("[Auth] Got server response: %s", response.body.c_str());
+                    if (not json.isArray()) {
+                        JAMI_ERR("[Auth] Can't parse server response: not an array");
+                    } else {
+                        for (unsigned i = 0, n = json.size(); i < n; i++) {
+                            const auto& e = json[i];
+                            Contact contact(e);
+                            this_->info_->contacts
+                                ->updateContact(dht::InfoHash {e["uri"].asString()}, contact);
                         }
-                    } catch (const std::exception& e) {
-                        JAMI_ERR("Error when iterating contact list: %s", e.what());
+                        this_->info_->contacts->saveContacts();
                     }
-                } else if (response.status_code == 401)
-                    this_.authError(TokenScope::Device);
+                } catch (const std::exception& e) {
+                    JAMI_ERR("Error when iterating contact list: %s", e.what());
+                }
+            } else if (response.status_code == 401)
+                this_->authError(TokenScope::Device);
 
-                this_.clearRequest(response.request);
-            });
+            this_->clearRequest(response.request);
         },
         logger_));
 
@@ -435,34 +423,33 @@ ServerAccountManager::syncDevices()
     sendDeviceRequest(std::make_shared<Request>(
         *Manager::instance().ioContext(),
         urlDevices,
-        [onAsync = onAsync_](Json::Value json, const dht::http::Response& response) {
-            onAsync([=](AccountManager& accountManager) {
-                JAMI_DBG("[Auth] Got request callback with status code=%u", response.status_code);
-                auto& this_ = *static_cast<ServerAccountManager*>(&accountManager);
-                if (response.status_code >= 200 && response.status_code < 300) {
-                    try {
-                        JAMI_WARN("[Auth] Got server response: %s", response.body.c_str());
-                        if (not json.isArray()) {
-                            JAMI_ERR("[Auth] Can't parse server response: not an array");
-                        } else {
-                            for (unsigned i = 0, n = json.size(); i < n; i++) {
-                                const auto& e = json[i];
-                                dht::PkId deviceId(e["deviceId"].asString());
-                                if (deviceId) {
-                                    this_.info_->contacts->foundAccountDevice(deviceId,
-                                                                              e["alias"].asString(),
-                                                                              clock::now());
-                                }
+        [w=weak_from_this()](Json::Value json, const dht::http::Response& response) {
+            JAMI_DBG("[Auth] Got request callback with status code=%u", response.status_code);
+            auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock());
+            if (!this_) return; 
+            if (response.status_code >= 200 && response.status_code < 300) {
+                try {
+                    JAMI_WARN("[Auth] Got server response: %s", response.body.c_str());
+                    if (not json.isArray()) {
+                        JAMI_ERR("[Auth] Can't parse server response: not an array");
+                    } else {
+                        for (unsigned i = 0, n = json.size(); i < n; i++) {
+                            const auto& e = json[i];
+                            dht::PkId deviceId(e["deviceId"].asString());
+                            if (deviceId) {
+                                this_->info_->contacts->foundAccountDevice(deviceId,
+                                                                            e["alias"].asString(),
+                                                                            clock::now());
                             }
                         }
-                    } catch (const std::exception& e) {
-                        JAMI_ERR("Error when iterating device list: %s", e.what());
                     }
-                } else if (response.status_code == 401)
-                    this_.authError(TokenScope::Device);
+                } catch (const std::exception& e) {
+                    JAMI_ERR("Error when iterating device list: %s", e.what());
+                }
+            } else if (response.status_code == 401)
+                this_->authError(TokenScope::Device);
 
-                this_.clearRequest(response.request);
-            });
+            this_->clearRequest(response.request);
         },
         logger_));
 }
@@ -482,25 +469,24 @@ ServerAccountManager::revokeDevice(const std::string& password,
     auto request = std::make_shared<Request>(
         *Manager::instance().ioContext(),
         url,
-        [cb, onAsync = onAsync_](Json::Value json, const dht::http::Response& response) {
-            onAsync([=](AccountManager& accountManager) {
-                JAMI_DBG("[Revoke] Got request callback with status code=%u", response.status_code);
-                auto& this_ = *static_cast<ServerAccountManager*>(&accountManager);
-                if (response.status_code >= 200 && response.status_code < 300) {
-                    try {
-                        JAMI_WARN("[Revoke] Got server response");
-                        if (json["errorDetails"].empty()) {
-                            if (cb)
-                                cb(RevokeDeviceResult::SUCCESS);
-                            this_.syncDevices();
-                        }
-                    } catch (const std::exception& e) {
-                        JAMI_ERR("Error when loading device list: %s", e.what());
+        [cb, w=weak_from_this()](Json::Value json, const dht::http::Response& response) {
+            JAMI_DBG("[Revoke] Got request callback with status code=%u", response.status_code);
+            auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock());
+            if (!this_) return; 
+            if (response.status_code >= 200 && response.status_code < 300) {
+                try {
+                    JAMI_WARN("[Revoke] Got server response");
+                    if (json["errorDetails"].empty()) {
+                        if (cb)
+                            cb(RevokeDeviceResult::SUCCESS);
+                        this_->syncDevices();
                     }
-                } else if (cb)
-                    cb(RevokeDeviceResult::ERROR_NETWORK);
-                this_.clearRequest(response.request);
-            });
+                } catch (const std::exception& e) {
+                    JAMI_ERR("Error when loading device list: %s", e.what());
+                }
+            } else if (cb)
+                cb(RevokeDeviceResult::ERROR_NETWORK);
+            this_->clearRequest(response.request);
         },
         logger_);
     request->set_method(restinio::http_method_delete());
@@ -523,40 +509,39 @@ ServerAccountManager::searchUser(const std::string& query, SearchCallback cb)
     sendDeviceRequest(std::make_shared<Request>(
         *Manager::instance().ioContext(),
         url,
-        [cb, onAsync = onAsync_](Json::Value json, const dht::http::Response& response) {
-            onAsync([=](AccountManager& accountManager) {
-                JAMI_DBG("[Search] Got request callback with status code=%u", response.status_code);
-                auto& this_ = *static_cast<ServerAccountManager*>(&accountManager);
-                if (response.status_code >= 200 && response.status_code < 300) {
-                    try {
-                        const auto& profiles = json["profiles"];
-                        Json::Value::ArrayIndex rcount = profiles.size();
-                        std::vector<std::map<std::string, std::string>> results;
-                        results.reserve(rcount);
-                        JAMI_WARN("[Search] Got server response: %s", response.body.c_str());
-                        for (Json::Value::ArrayIndex i = 0; i < rcount; i++) {
-                            const auto& ruser = profiles[i];
-                            std::map<std::string, std::string> user;
-                            for (const auto& member : ruser.getMemberNames()) {
-                                const auto& rmember = ruser[member];
-                                if (rmember.isString())
-                                    user[member] = rmember.asString();
-                            }
-                            results.emplace_back(std::move(user));
+        [cb, w=weak_from_this()](Json::Value json, const dht::http::Response& response) {
+            JAMI_DBG("[Search] Got request callback with status code=%u", response.status_code);
+            auto this_ = std::static_pointer_cast<ServerAccountManager>(w.lock());
+            if (!this_) return; 
+            if (response.status_code >= 200 && response.status_code < 300) {
+                try {
+                    const auto& profiles = json["profiles"];
+                    Json::Value::ArrayIndex rcount = profiles.size();
+                    std::vector<std::map<std::string, std::string>> results;
+                    results.reserve(rcount);
+                    JAMI_WARN("[Search] Got server response: %s", response.body.c_str());
+                    for (Json::Value::ArrayIndex i = 0; i < rcount; i++) {
+                        const auto& ruser = profiles[i];
+                        std::map<std::string, std::string> user;
+                        for (const auto& member : ruser.getMemberNames()) {
+                            const auto& rmember = ruser[member];
+                            if (rmember.isString())
+                                user[member] = rmember.asString();
                         }
-                        if (cb)
-                            cb(results, SearchResponse::found);
-                    } catch (const std::exception& e) {
-                        JAMI_ERR("[Search] Error during search: %s", e.what());
+                        results.emplace_back(std::move(user));
                     }
-                } else {
-                    if (response.status_code == 401)
-                        this_.authError(TokenScope::Device);
                     if (cb)
-                        cb({}, SearchResponse::error);
+                        cb(results, SearchResponse::found);
+                } catch (const std::exception& e) {
+                    JAMI_ERR("[Search] Error during search: %s", e.what());
                 }
-                this_.clearRequest(response.request);
-            });
+            } else {
+                if (response.status_code == 401)
+                    this_->authError(TokenScope::Device);
+                if (cb)
+                    cb({}, SearchResponse::error);
+            }
+            this_->clearRequest(response.request);
         },
         logger_));
     return true;
diff --git a/src/jamidht/server_account_manager.h b/src/jamidht/server_account_manager.h
index dd94248715df9820695df3543f27565b97f57438..82e24d64c986197700acb0255bc586a10b85ee6e 100644
--- a/src/jamidht/server_account_manager.h
+++ b/src/jamidht/server_account_manager.h
@@ -30,7 +30,6 @@ class ServerAccountManager : public AccountManager
 {
 public:
     ServerAccountManager(const std::string& path,
-                         OnAsync&& onAsync,
                          const std::string& managerHostname,
                          const std::string& nameServer);