diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index 90689c4c4d4d9872aa48a2290e81e41db434e7b7..ccc86b0ae2bb3f1a02cf193c6adb265275c5caee 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -275,7 +275,16 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall
             }
             IdtyEvent::Confirmed => {}
             IdtyEvent::Validated => {}
-            IdtyEvent::Removed => {}
+            IdtyEvent::Removed => {
+                if let Err(e) = pallet_membership::Pallet::<T, I>::revoke_membership(
+                    RawOrigin::Root.into(),
+                    Some(idty_index),
+                ) {
+                    sp_std::if_std! {
+                        println!("fail to revoke membership: {:?}", e)
+                    }
+                }
+            }
         }
         0
     }
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index e3c39d5e1dc9a8aaf460286d4faa88d1a669a8a8..485a9625338f5f47c1a4307d9e26cf81b5babe7d 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -20,7 +20,7 @@ use frame_support::{parameter_types, traits::Everything};
 use frame_system as system;
 use sp_core::H256;
 use sp_runtime::{
-    testing::Header,
+    testing::{Header, TestSignature, UintAuthorityId},
     traits::{BlakeTwo256, IdentityLookup},
 };
 use std::collections::BTreeMap;
@@ -118,6 +118,8 @@ impl pallet_identity::Config for Test {
     type OnIdtyChange = DuniterWot;
     type MaxDisabledPeriod = MaxDisabledPeriod;
     type RemoveIdentityConsumers = ();
+    type RevocationSigner = UintAuthorityId;
+    type RevocationSignature = TestSignature;
 }
 
 // Membership
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index f76323b09451882266a99d11406ca50a9fd1da31..6f0602a324e95a11dd423beb271ccbf71b2ccea4 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -35,7 +35,7 @@ pub use types::*;
 use crate::traits::*;
 use codec::Codec;
 use frame_support::dispatch::Weight;
-use sp_runtime::traits::{AtLeast32BitUnsigned, One, Saturating, Zero};
+use sp_runtime::traits::{AtLeast32BitUnsigned, IdentifyAccount, One, Saturating, Verify, Zero};
 use sp_std::fmt::Debug;
 use sp_std::prelude::*;
 
@@ -93,6 +93,10 @@ pub mod pallet {
         /// Handle the logic that remove all identity consumers.
         /// "identity consumers" mean all things that rely on the existence of the identity.
         type RemoveIdentityConsumers: RemoveIdentityConsumers<Self::IdtyIndex>;
+        /// Signing key of revocation payload
+        type RevocationSigner: IdentifyAccount<AccountId = Self::AccountId>;
+        /// Signature of revocation payload
+        type RevocationSignature: Parameter + Verify<Signer = Self::RevocationSigner>;
     }
 
     // GENESIS STUFFĂ‚ //
@@ -362,6 +366,28 @@ pub mod pallet {
 
             Ok(().into())
         }
+        #[pallet::weight(0)]
+        pub fn revoke_identity(
+            origin: OriginFor<T>,
+            payload: RevocationPayload<T::AccountId, T::Hash>,
+            payload_sig: T::RevocationSignature,
+        ) -> DispatchResultWithPostInfo {
+            let _ = ensure_signed(origin)?;
+            if payload.genesis_hash != frame_system::Pallet::<T>::block_hash(T::BlockNumber::zero())
+            {
+                return Err(Error::<T>::BadGenesisHash.into());
+            }
+            if !payload.using_encoded(|bytes| payload_sig.verify(bytes, &payload.owner_key)) {
+                return Err(Error::<T>::BadProof.into());
+            }
+            if let Some(idty_index) = <IdentityIndexOf<T>>::take(payload.owner_key) {
+                Self::do_remove_identity(idty_index);
+                Ok(().into())
+            } else {
+                Err(Error::<T>::IdtyNotFound.into())
+            }
+        }
+
         #[pallet::weight(0)]
         pub fn remove_identity(
             origin: OriginFor<T>,
@@ -418,6 +444,10 @@ pub mod pallet {
 
     #[pallet::error]
     pub enum Error<T> {
+        /// Genesis hash does not match
+        BadGenesisHash,
+        /// Signature is invalid
+        BadProof,
         /// Creator not allowed to create identities
         CreatorNotAllowedToCreateIdty,
         /// Identity already confirmed
diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs
index 7a19d32d3cc8849aa5b5795261c3c898f6fe12c5..159ca65949e62c49dd966cf9f6bc7a3bcb65aaef 100644
--- a/pallets/identity/src/mock.rs
+++ b/pallets/identity/src/mock.rs
@@ -23,7 +23,7 @@ use frame_support::{
 use frame_system as system;
 use sp_core::H256;
 use sp_runtime::{
-    testing::Header,
+    testing::{Header, TestSignature, UintAuthorityId},
     traits::{BlakeTwo256, IdentityLookup, IsMember},
 };
 
@@ -110,6 +110,8 @@ impl pallet_identity::Config for Test {
     type OnIdtyChange = ();
     type MaxDisabledPeriod = MaxDisabledPeriod;
     type RemoveIdentityConsumers = ();
+    type RevocationSigner = UintAuthorityId;
+    type RevocationSignature = TestSignature;
 }
 
 // Build genesis storage according to the mock runtime.
diff --git a/pallets/identity/src/tests.rs b/pallets/identity/src/tests.rs
index 885b1cd009f5d805d18585c3628467d6d528cbd4..fc734019050e2367745906d9cfac5dacc80d9432 100644
--- a/pallets/identity/src/tests.rs
+++ b/pallets/identity/src/tests.rs
@@ -15,10 +15,12 @@
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
 use crate::mock::*;
-use crate::{Error, GenesisIdty, IdtyName, IdtyValue};
+use crate::{Error, GenesisIdty, IdtyName, IdtyValue, RevocationPayload};
+use codec::Encode;
 //use frame_support::assert_err;
 use frame_support::assert_ok;
 use frame_system::{EventRecord, Phase};
+use sp_runtime::testing::TestSignature;
 
 type IdtyVal = IdtyValue<u64, u64>;
 
@@ -123,3 +125,47 @@ fn test_idty_creation_period() {
         );
     });
 }
+
+#[test]
+fn test_idty_revocation() {
+    new_test_ext(IdentityConfig {
+        identities: vec![alice()],
+    })
+    .execute_with(|| {
+        // We need to initialize at least one block before any call
+        run_to_block(1);
+
+        let revocation_payload = RevocationPayload {
+            owner_key: 1,
+            genesis_hash: System::block_hash(0),
+        };
+
+        // Payload must be signed by the right identity
+        assert_eq!(
+            Identity::revoke_identity(
+                Origin::signed(1),
+                revocation_payload.clone(),
+                TestSignature(42, revocation_payload.encode())
+            ),
+            Err(Error::<Test>::BadProof.into())
+        );
+
+        // Anyone can submit a revocation payload
+        assert_ok!(Identity::revoke_identity(
+            Origin::signed(42),
+            revocation_payload.clone(),
+            TestSignature(1, revocation_payload.encode())
+        ));
+
+        let events = System::events();
+        assert_eq!(events.len(), 1);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(crate::Event::IdtyRemoved { idty_index: 1 }),
+                topics: vec![],
+            }
+        );
+    });
+}
diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs
index d6991ce60acdfd98e60a775c278804cf9f2bfd0c..02931d2243441f804253657780a27a050a03cf37 100644
--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -85,3 +85,10 @@ pub struct IdtyValue<BlockNumber, AccountId> {
     pub removable_on: BlockNumber,
     pub status: IdtyStatus,
 }
+
+#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo, RuntimeDebug)]
+pub struct RevocationPayload<AccountId, Hash> {
+    pub owner_key: AccountId,
+    // Avoid replay attack between blockchains
+    pub genesis_hash: Hash,
+}
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index e1beb6b255d1dd2ef0402e6908d108b1df04e751..7b78f62dbec9dd55dbe7d375cd4b5fac793934a7 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -367,6 +367,8 @@ macro_rules! pallets_config {
 			type OnIdtyChange = Wot;
 			type MaxDisabledPeriod = MaxDisabledPeriod;
 			type RemoveIdentityConsumers = RemoveIdentityConsumersImpl<Self>;
+			type RevocationSigner = <Signature as sp_runtime::traits::Verify>::Signer;
+			type RevocationSignature = Signature;
 		}
 
 		impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {