diff --git a/Cargo.lock b/Cargo.lock
index 9c56b56a52e47e3850f5ebd6cb2589c25c2db092..4cb2d89c8e0e7be6768fb1b9bb8f77ba2b7d0cf0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -855,6 +855,7 @@ dependencies = [
  "frame-system",
  "pallet-certification",
  "pallet-identity",
+ "pallet-membership",
  "pallet-session",
  "pallet-ud-accounts-storage",
  "parity-scale-codec",
@@ -1461,6 +1462,7 @@ dependencies = [
  "sp-finality-grandpa",
  "sp-inherents",
  "sp-keyring",
+ "sp-membership",
  "sp-offchain",
  "sp-runtime",
  "sp-session",
@@ -2120,6 +2122,7 @@ dependencies = [
  "pallet-grandpa",
  "pallet-identity",
  "pallet-im-online",
+ "pallet-membership",
  "pallet-multisig",
  "pallet-offences",
  "pallet-scheduler",
@@ -2174,6 +2177,7 @@ dependencies = [
  "pallet-certification",
  "pallet-grandpa",
  "pallet-identity",
+ "pallet-membership",
  "pallet-multisig",
  "pallet-scheduler",
  "pallet-sudo",
@@ -2363,6 +2367,7 @@ dependencies = [
  "pallet-grandpa",
  "pallet-identity",
  "pallet-im-online",
+ "pallet-membership",
  "pallet-multisig",
  "pallet-offences",
  "pallet-scheduler",
@@ -4549,6 +4554,7 @@ dependencies = [
  "serde",
  "sp-core",
  "sp-io",
+ "sp-membership",
  "sp-runtime",
  "sp-std",
 ]
@@ -4585,6 +4591,7 @@ dependencies = [
  "serde",
  "sp-core",
  "sp-io",
+ "sp-membership",
  "sp-runtime",
  "sp-std",
 ]
@@ -7392,6 +7399,17 @@ dependencies = [
  "zstd",
 ]
 
+[[package]]
+name = "sp-membership"
+version = "3.0.0"
+dependencies = [
+ "frame-support",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-std",
+]
+
 [[package]]
 name = "sp-offchain"
 version = "4.0.0-dev"
diff --git a/Cargo.toml b/Cargo.toml
index 2e4c71d5e414d89f9a366e0aac03a57b6b76557a..f5f8a0a024c97a655e41a8b1a12d3fe42ae137cd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ members = [
 	'pallets/membership',
     'pallets/ud-accounts-storage',
     'pallets/universal-dividend',
+    'primitives/membership',
 ]
 
 # The list of dependencies below (which can be both direct and indirect dependencies) are crates
diff --git a/node/Cargo.toml b/node/Cargo.toml
index 313c494a377790d669cefef3ba5ed3bfb5b79891..45e9a5e2446c6c7bf1d0ae03fb136150dc64b8dd 100644
--- a/node/Cargo.toml
+++ b/node/Cargo.toml
@@ -43,6 +43,7 @@ g1-runtime = { path = '../runtime/g1', optional = true }
 gdev-runtime = { path = '../runtime/gdev', optional = true }
 gtest-runtime = { path = '../runtime/gtest', optional = true }
 pallet-certification = { path = '../pallets/certification' }
+sp-membership = { path = '../primitives/membership' }
 
 # crates.io dependencies
 async-io = "1.3"
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index aeb45dfd21511480a43a8765387d01e7703c2f5c..133dddd494a7aa97b0e2b13224941c3a6fccbc84 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -18,13 +18,14 @@ use super::*;
 use common_runtime::entities::IdtyName;
 use gdev_runtime::{
     AccountId, BalancesConfig, GenesisConfig, GrandpaConfig, IdentityConfig, IdtyRight, IdtyValue,
-    StrongCertConfig, SudoConfig, SystemConfig, UdAccountsStorageConfig, UniversalDividendConfig,
-    WASM_BINARY,
+    MembershipConfig, StrongCertConfig, SudoConfig, SystemConfig, UdAccountsStorageConfig,
+    UniversalDividendConfig, WASM_BINARY,
 };
 use maplit::btreemap;
 use sc_service::ChainType;
 use sp_core::sr25519;
 use sp_finality_grandpa::AuthorityId as GrandpaId;
+use sp_membership::MembershipData;
 use std::collections::BTreeMap;
 
 pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
@@ -112,12 +113,10 @@ fn devnet_genesis(
                 .iter()
                 .map(|(name, account)| IdtyValue {
                     data: Default::default(),
-                    expire_on: gdev_runtime::MaxInactivityPeriod::get(),
                     owner_key: account.clone(),
                     name: name.clone(),
                     next_creatable_identity_on: Default::default(),
                     removable_on: 0,
-                    renewable_on: gdev_runtime::StrongCertRenewablePeriod::get(),
                     rights: vec![
                         (IdtyRight::CreateIdty, None),
                         (IdtyRight::StrongCert, None),
@@ -127,6 +126,19 @@ fn devnet_genesis(
                 })
                 .collect(),
         },
+        membership: MembershipConfig {
+            memberships: (1..=initial_identities.len())
+                .map(|i| {
+                    (
+                        i as u32,
+                        MembershipData {
+                            expire_on: gdev_runtime::MembershipPeriod::get(),
+                            renewable_on: gdev_runtime::RenewablePeriod::get(),
+                        },
+                    )
+                })
+                .collect(),
+        },
         strong_cert: StrongCertConfig {
             certs_by_issuer: clique_wot(
                 initial_identities.len(),
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index 15fae450ae495dbfec5449c3fd05d76699a11e6a..36e228cdb3f3f1c7df59b7c2f15beb5e22d4528a 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -19,8 +19,8 @@ use common_runtime::constants::*;
 use common_runtime::entities::IdtyName;
 use gtest_runtime::{
     opaque::SessionKeys, AccountId, BabeConfig, BalancesConfig, GenesisConfig, IdentityConfig,
-    IdtyRight, IdtyValue, ImOnlineId, SessionConfig, StrongCertConfig, SudoConfig, SystemConfig,
-    UdAccountsStorageConfig, UniversalDividendConfig, WASM_BINARY,
+    IdtyRight, IdtyValue, ImOnlineId, MembershipConfig, SessionConfig, StrongCertConfig,
+    SudoConfig, SystemConfig, UdAccountsStorageConfig, UniversalDividendConfig, WASM_BINARY,
 };
 use maplit::btreemap;
 use sc_service::ChainType;
@@ -28,6 +28,7 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use sp_consensus_babe::AuthorityId as BabeId;
 use sp_core::sr25519;
 use sp_finality_grandpa::AuthorityId as GrandpaId;
+use sp_membership::MembershipData;
 use std::collections::BTreeMap;
 
 pub type AuthorityKeys = (
@@ -99,18 +100,29 @@ fn devnet_genesis(
             identities: initial_identities
                 .iter()
                 .map(|(name, account)| IdtyValue {
+                    data: Default::default(),
                     name: name.clone(),
-                    expire_on: gtest_runtime::MaxInactivityPeriod::get(),
                     owner_key: account.clone(),
                     removable_on: 0,
-                    renewable_on: gtest_runtime::StrongCertRenewablePeriod::get(),
                     rights: vec![
                         (IdtyRight::CreateIdty, None),
                         (IdtyRight::StrongCert, None),
                         (IdtyRight::Ud, None),
                     ],
                     status: gtest_runtime::IdtyStatus::Validated,
-                    data: Default::default(),
+                })
+                .collect(),
+        },
+        membership: MembershipConfig {
+            memberships: (1..=initial_identities.len())
+                .map(|i| {
+                    (
+                        i as u32,
+                        MembershipData {
+                            expire_on: gtest_runtime::MembershipPeriod::get(),
+                            renewable_on: gtest_runtime::RenewablePeriod::get(),
+                        },
+                    )
                 })
                 .collect(),
         },
@@ -292,18 +304,29 @@ fn testnet_genesis(
             identities: initial_identities
                 .iter()
                 .map(|(name, account)| IdtyValue {
+                    data: Default::default(),
                     name: name.clone(),
-                    expire_on: gtest_runtime::MaxInactivityPeriod::get(),
                     owner_key: account.clone(),
                     removable_on: 0,
-                    renewable_on: gtest_runtime::StrongCertRenewablePeriod::get(),
                     rights: vec![
                         (IdtyRight::CreateIdty, None),
                         (IdtyRight::StrongCert, None),
                         (IdtyRight::Ud, None),
                     ],
                     status: gtest_runtime::IdtyStatus::Validated,
-                    data: Default::default(),
+                })
+                .collect(),
+        },
+        membership: MembershipConfig {
+            memberships: (1..=initial_identities.len())
+                .map(|i| {
+                    (
+                        i as u32,
+                        MembershipData {
+                            expire_on: gtest_runtime::MembershipPeriod::get(),
+                            renewable_on: gtest_runtime::RenewablePeriod::get(),
+                        },
+                    )
                 })
                 .collect(),
         },
diff --git a/pallets/identity/Cargo.toml b/pallets/identity/Cargo.toml
index 0fbcb113af30a5822a592fc16b3a46e203f4b077..d7b804275173c23321b94b0084a87e9b5305039e 100644
--- a/pallets/identity/Cargo.toml
+++ b/pallets/identity/Cargo.toml
@@ -19,12 +19,14 @@ std = [
     'frame-benchmarking/std',
     'serde',
     'sp-core/std',
+    'sp-membership/std',
     'sp-runtime/std',
 	'sp-std/std',
 ]
 try-runtime = ['frame-support/try-runtime']
 
 [dependencies]
+sp-membership = { path = "../../primitives/membership", default-features = false }
 
 # substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
@@ -81,6 +83,5 @@ version = '1.0.119'
 ### DEV ###
 
 [dev-dependencies.sp-io]
-default-features = false
 git = 'https://github.com/librelois/substrate.git'
 branch = 'duniter-monthly-2022-01'
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index c7da9310720a2be4862a0d94ff3c1726e2be6dea..7ce3a9c33088874ac26d335682040ac7bc84bf20 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -35,6 +35,7 @@ pub use types::*;
 use crate::traits::*;
 use codec::Codec;
 use frame_support::dispatch::Weight;
+use frame_system::RawOrigin;
 use sp_runtime::traits::{AtLeast32BitUnsigned, One, Saturating, Zero};
 use sp_std::fmt::Debug;
 use sp_std::prelude::*;
@@ -43,10 +44,20 @@ use sp_std::prelude::*;
 pub mod pallet {
     use super::*;
     use frame_support::pallet_prelude::*;
+    use frame_support::traits::StorageVersion;
     use frame_system::pallet_prelude::*;
-    use scale_info::TypeInfo;
+    use sp_membership::traits::MembershipAction as _;
+
+    /// The current storage version.
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::generate_store(pub(super) trait Store)]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    pub struct Pallet<T>(_);
+
+    // CONFIG //
 
-    /// Configure the pallet by specifying the parameters and types on which it depends.
     #[pallet::config]
     pub trait Config: frame_system::Config {
         #[pallet::constant]
@@ -87,83 +98,13 @@ pub mod pallet {
         /// On right key change
         type OnRightKeyChange: OnRightKeyChange<Self>;
         #[pallet::constant]
-        /// Maximum period of inactivity, after this period, the identity is permanently deleted
-        type MaxInactivityPeriod: Get<Self::BlockNumber>;
-        #[pallet::constant]
         /// Maximum period with no rights, after this period, the identity is permanently deleted
         type MaxNoRightPeriod: Get<Self::BlockNumber>;
-        /// Duration after which an identity is renewable
-        type RenewablePeriod: Get<Self::BlockNumber>;
-        #[pallet::constant]
-        /// Period after which a non-validated identity is deleted
-        type ValidationPeriod: Get<Self::BlockNumber>;
-    }
-
-    // STORAGE //
-
-    #[pallet::pallet]
-    #[pallet::generate_store(pub(super) trait Store)]
-    pub struct Pallet<T>(_);
-
-    // A value placed in storage that represents the current version of the Balances storage.
-    // This value is used by the `on_runtime_upgrade` logic to determine whether we run
-    // storage migration logic. This should match directly with the semantic versions of the Rust crate.
-    #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-    pub enum Releases {
-        V1_0_0,
+        ///
+        type Membership: sp_membership::traits::MembershipAction<Self::IdtyIndex, Self::Origin>;
     }
-    impl Default for Releases {
-        fn default() -> Self {
-            Releases::V1_0_0
-        }
-    }
-
-    /// Storage version of the pallet.
-    #[pallet::storage]
-    pub(super) type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
-
-    /// Identities
-    #[pallet::storage]
-    #[pallet::getter(fn identity)]
-    pub type Identities<T: Config> = StorageMap<
-        _,
-        Blake2_128Concat,
-        T::IdtyIndex,
-        IdtyValue<T::AccountId, T::BlockNumber, T::IdtyData, T::IdtyRight>,
-        OptionQuery,
-    >;
-
-    /// IdentitiesByDid
-    #[pallet::storage]
-    #[pallet::getter(fn identity_by_did)]
-    pub type IdentitiesByDid<T: Config> =
-        StorageMap<_, Blake2_128Concat, IdtyName, T::IdtyIndex, ValueQuery>;
 
-    #[pallet::storage]
-    pub(super) type NextIdtyIndex<T: Config> = StorageValue<_, T::IdtyIndex, ValueQuery>;
-
-    #[pallet::storage]
-    #[pallet::getter(fn identities_count)]
-    pub(super) type IdentitiesCount<T: Config> = StorageValue<_, u64, ValueQuery>;
-
-    /// Identities by expiration block
-    #[pallet::storage]
-    #[pallet::getter(fn expire_on)]
-    pub type IdentitiesExpireOn<T: Config> =
-        StorageMap<_, Blake2_128Concat, T::BlockNumber, Vec<T::IdtyIndex>, ValueQuery>;
-
-    /// Identities by removed block
-    #[pallet::storage]
-    #[pallet::getter(fn removable_on)]
-    pub type IdentitiesRemovableOn<T: Config> = StorageMap<
-        _,
-        Blake2_128Concat,
-        T::BlockNumber,
-        Vec<(T::IdtyIndex, IdtyStatus)>,
-        ValueQuery,
-    >;
-
-    // GENESIS //
+    // GENESIS STUFFĂ‚ //
     #[pallet::genesis_config]
     pub struct GenesisConfig<T: Config> {
         pub identities: Vec<IdtyValue<T::AccountId, T::BlockNumber, T::IdtyData, T::IdtyRight>>,
@@ -205,7 +146,6 @@ pub mod pallet {
             let mut identities = self.identities.clone();
             identities.sort_by(|idty_val_1, idty_val_2| idty_val_1.name.cmp(&idty_val_2.name));
 
-            <StorageVersion<T>>::put(Releases::V1_0_0);
             <IdentitiesCount<T>>::put(self.identities.len() as u64);
             for idty_value in &identities {
                 let idty_index = Pallet::<T>::get_next_idty_index();
@@ -220,13 +160,50 @@ pub mod pallet {
         }
     }
 
+    // STORAGE //
+
+    /// Identities
+    #[pallet::storage]
+    #[pallet::getter(fn identity)]
+    pub type Identities<T: Config> = StorageMap<
+        _,
+        Blake2_128Concat,
+        T::IdtyIndex,
+        IdtyValue<T::AccountId, T::BlockNumber, T::IdtyData, T::IdtyRight>,
+        OptionQuery,
+    >;
+
+    /// IdentitiesByDid
+    #[pallet::storage]
+    #[pallet::getter(fn identity_by_did)]
+    pub type IdentitiesByDid<T: Config> =
+        StorageMap<_, Blake2_128Concat, IdtyName, T::IdtyIndex, ValueQuery>;
+
+    #[pallet::storage]
+    pub(super) type NextIdtyIndex<T: Config> = StorageValue<_, T::IdtyIndex, ValueQuery>;
+
+    #[pallet::storage]
+    #[pallet::getter(fn identities_count)]
+    pub(super) type IdentitiesCount<T: Config> = StorageValue<_, u64, ValueQuery>;
+
+    /// Identities by removed block
+    #[pallet::storage]
+    #[pallet::getter(fn removable_on)]
+    pub type IdentitiesRemovableOn<T: Config> = StorageMap<
+        _,
+        Blake2_128Concat,
+        T::BlockNumber,
+        Vec<(T::IdtyIndex, IdtyStatus)>,
+        ValueQuery,
+    >;
+
     // HOOKS //
 
     #[pallet::hooks]
     impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
         fn on_initialize(n: T::BlockNumber) -> Weight {
             if n > T::BlockNumber::zero() {
-                Self::expire_identities(n) + Self::prune_identities(n)
+                Self::prune_identities(n)
             } else {
                 0
             }
@@ -282,46 +259,67 @@ pub mod pallet {
             idty_name: IdtyName,
             owner_key: T::AccountId,
         ) -> DispatchResultWithPostInfo {
+            // Verification phase //
+            let who = ensure_signed(origin)?;
+
             let creator_idty_val =
                 Identities::<T>::try_get(&creator).map_err(|_| Error::<T>::CreatorNotExist)?;
 
+            let expected_account = if let Ok(index) = creator_idty_val
+                .rights
+                .binary_search_by(|(right_, _)| right_.cmp(&T::IdtyRight::create_idty_right()))
+            {
+                creator_idty_val.rights[index]
+                    .1
+                    .clone()
+                    .unwrap_or(creator_idty_val.owner_key)
+            } else {
+                return Err(Error::<T>::CreatorNotHaveRightToCreateIdty.into());
+            };
+
+            if who != expected_account {
+                return Err(Error::<T>::RequireToBeOwner.into());
+            }
+
             let block_number = frame_system::pallet::Pallet::<T>::block_number();
 
-            if creator_idty_val.next_creatable_identity_on
-                > block_number + T::IdtyCreationPeriod::get()
-            {
+            if creator_idty_val.next_creatable_identity_on > block_number {
                 return Err(Error::<T>::NotRespectIdtyCreationPeriod.into());
             }
 
-            T::EnsureIdtyCallAllowed::can_create_identity(
-                origin,
-                creator,
-                creator_idty_val,
-                &idty_name,
-                &owner_key,
-            )?;
+            if !T::EnsureIdtyCallAllowed::can_create_identity(creator) {
+                return Err(Error::<T>::CreatorNotAllowedToCreateIdty.into());
+            }
 
             if !T::IdtyNameValidator::validate(&idty_name) {
                 return Err(Error::<T>::IdtyNameInvalid.into());
             }
-            let idty_data =
-                T::IdtyDataProvider::provide_identity_data(creator, &idty_name, &owner_key);
             if <IdentitiesByDid<T>>::contains_key(&idty_name) {
                 return Err(Error::<T>::IdtyNameAlreadyExist.into());
             }
 
+            // Apply phase //
+
+            <Identities<T>>::mutate_exists(creator, |idty_val_opt| {
+                if let Some(ref mut idty_val) = idty_val_opt {
+                    idty_val.next_creatable_identity_on =
+                        block_number + T::IdtyCreationPeriod::get();
+                }
+            });
+
+            let idty_data =
+                T::IdtyDataProvider::provide_identity_data(creator, &idty_name, &owner_key);
+
             let removable_on = block_number + T::ConfirmPeriod::get();
 
             let idty_index = Self::get_next_idty_index();
             <Identities<T>>::insert(
                 idty_index,
                 IdtyValue {
-                    expire_on: T::BlockNumber::zero(),
                     name: idty_name.clone(),
                     next_creatable_identity_on: T::BlockNumber::zero(),
                     owner_key: owner_key.clone(),
                     removable_on,
-                    renewable_on: T::BlockNumber::zero(),
                     rights: Vec::with_capacity(0),
                     status: IdtyStatus::Created,
                     data: idty_data,
@@ -347,22 +345,11 @@ pub mod pallet {
                     if idty_value.status != IdtyStatus::Created {
                         return Err(Error::<T>::IdtyAlreadyConfirmed.into());
                     }
+                    T::Membership::request_membership_(RawOrigin::Signed(who).into(), idty_index)?;
 
-                    let block_number = frame_system::pallet::Pallet::<T>::block_number();
-                    let expire_on = block_number + T::MaxInactivityPeriod::get();
-                    let removable_on = block_number + T::ValidationPeriod::get();
-                    let renewable_on = block_number + T::RenewablePeriod::get();
-                    idty_value.expire_on = expire_on;
-                    idty_value.removable_on = removable_on;
-                    idty_value.renewable_on = renewable_on;
                     idty_value.status = IdtyStatus::ConfirmedByOwner;
 
                     <Identities<T>>::insert(idty_index, idty_value);
-                    IdentitiesExpireOn::<T>::append(expire_on, idty_index);
-                    IdentitiesRemovableOn::<T>::append(
-                        removable_on,
-                        (idty_index, IdtyStatus::ConfirmedByOwner),
-                    );
                     Self::deposit_event(Event::IdtyConfirmed(idty_name));
                     T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Confirmed);
                     Ok(().into())
@@ -388,19 +375,15 @@ pub mod pallet {
                             Err(Error::<T>::IdtyNotValidated.into())
                         }
                         IdtyStatus::Validated | IdtyStatus::Expired => {
-                            let block_number = frame_system::pallet::Pallet::<T>::block_number();
-                            if idty_value.renewable_on > block_number {
-                                return Err(Error::<T>::IdtyNotYetRenewable.into());
-                            }
-                            let expire_on = block_number + T::MaxInactivityPeriod::get();
-                            let renewable_on = block_number + T::RenewablePeriod::get();
-                            idty_value.expire_on = expire_on;
-                            idty_value.renewable_on = renewable_on;
+                            let _post_info = T::Membership::renew_membership_(
+                                RawOrigin::Signed(who).into(),
+                                idty_index,
+                            )?;
+
                             let old_status = idty_value.status;
                             idty_value.status = IdtyStatus::Validated;
 
                             <Identities<T>>::insert(idty_index, idty_value);
-                            IdentitiesExpireOn::<T>::append(expire_on, idty_index);
                             Self::deposit_event(Event::IdtyRenewed(idty_name));
                             if old_status == IdtyStatus::Expired {
                                 T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Validated);
@@ -420,12 +403,14 @@ pub mod pallet {
             origin: OriginFor<T>,
             idty_index: T::IdtyIndex,
         ) -> DispatchResultWithPostInfo {
-            T::IdtyValidationOrigin::ensure_origin(origin)?;
+            T::IdtyValidationOrigin::ensure_origin(origin.clone())?;
 
             if let Ok(mut idty_value) = <Identities<T>>::try_get(idty_index) {
                 match idty_value.status {
                     IdtyStatus::Created => Err(Error::<T>::IdtyNotConfirmedByOwner.into()),
                     IdtyStatus::ConfirmedByOwner => {
+                        let _post_info = T::Membership::claim_membership_(origin, idty_index)?;
+
                         let block_number = frame_system::pallet::Pallet::<T>::block_number();
                         let removable_on = block_number + T::MaxNoRightPeriod::get();
                         idty_value.removable_on = removable_on;
@@ -647,6 +632,10 @@ pub mod pallet {
     pub enum Error<T> {
         /// Creator not exist
         CreatorNotExist,
+        /// Creator not allowed to create identities
+        CreatorNotAllowedToCreateIdty,
+        /// Creator not have right to create identities
+        CreatorNotHaveRightToCreateIdty,
         /// Identity already confirmed
         IdtyAlreadyConfirmed,
         /// Identity already validated
@@ -697,6 +686,33 @@ pub mod pallet {
                 panic!("storage corrupted")
             }
         }
+        pub(super) fn do_expire_identity(idty_index: T::IdtyIndex) -> Weight {
+            let mut total_weight: Weight = 0;
+
+            let block_number = frame_system::pallet::Pallet::<T>::block_number();
+            let removable_on = block_number + T::MaxNoRightPeriod::get();
+            <Identities<T>>::mutate_exists(idty_index, |idty_val_opt| {
+                if let Some(ref mut idty_val) = idty_val_opt {
+                    idty_val.removable_on = removable_on;
+                    idty_val.rights = Vec::with_capacity(0);
+                }
+            });
+            <IdentitiesRemovableOn<T>>::append(removable_on, (idty_index, IdtyStatus::Expired));
+            total_weight += T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Expired);
+
+            total_weight
+        }
+        pub(super) fn do_remove_identity(idty_index: T::IdtyIndex) -> Weight {
+            let mut total_weight: Weight = 0;
+
+            if let Some(idty_val) = <Identities<T>>::take(idty_index) {
+                <IdentitiesByDid<T>>::remove(idty_val.name);
+            }
+            Self::dec_identities_counter();
+            total_weight += T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Removed);
+
+            total_weight
+        }
         fn get_next_idty_index() -> T::IdtyIndex {
             if let Ok(next_index) = <NextIdtyIndex<T>>::try_get() {
                 <NextIdtyIndex<T>>::put(next_index.saturating_add(T::IdtyIndex::one()));
@@ -713,24 +729,17 @@ pub mod pallet {
                 <IdentitiesCount<T>>::put(1);
             }
         }
-        fn expire_identities(block_number: T::BlockNumber) -> Weight {
+        fn prune_identities(block_number: T::BlockNumber) -> Weight {
             let mut total_weight: Weight = 0;
 
             use frame_support::storage::generator::StorageMap as _;
-            if let Some(identities_index) = IdentitiesExpireOn::<T>::from_query_to_optional_value(
-                IdentitiesExpireOn::<T>::take(block_number),
+            if let Some(identities) = IdentitiesRemovableOn::<T>::from_query_to_optional_value(
+                IdentitiesRemovableOn::<T>::take(block_number),
             ) {
-                for idty_index in identities_index {
+                for (idty_index, idty_status) in identities {
                     if let Ok(idty_val) = <Identities<T>>::try_get(idty_index) {
-                        if idty_val.expire_on == block_number {
-                            <Identities<T>>::mutate_exists(idty_index, |idty_val_opt| {
-                                if let Some(ref mut idty_val) = idty_val_opt {
-                                    idty_val.rights = Vec::with_capacity(0);
-                                    idty_val.status = IdtyStatus::Expired;
-                                }
-                            });
-                            total_weight +=
-                                T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Expired);
+                        if idty_val.removable_on == block_number && idty_val.status == idty_status {
+                            total_weight += Self::do_remove_identity(idty_index)
                         }
                     }
                 }
@@ -738,28 +747,47 @@ pub mod pallet {
 
             total_weight
         }
-        fn prune_identities(block_number: T::BlockNumber) -> Weight {
-            let mut total_weight: Weight = 0;
+    }
+}
 
-            use frame_support::storage::generator::StorageMap as _;
-            if let Some(identities) = IdentitiesRemovableOn::<T>::from_query_to_optional_value(
-                IdentitiesRemovableOn::<T>::take(block_number),
-            ) {
-                for (idty_index, idty_status) in identities {
-                    if let Ok(idty_val) = <Identities<T>>::try_get(idty_index) {
-                        if idty_val.removable_on == block_number && idty_val.status == idty_status {
-                            let name = idty_val.name;
-                            <Identities<T>>::remove(idty_index);
-                            <IdentitiesByDid<T>>::remove(name);
-                            Self::dec_identities_counter();
-                            total_weight +=
-                                T::OnIdtyChange::on_idty_change(idty_index, IdtyEvent::Removed);
-                        }
+impl<T: Config> sp_membership::traits::IsOriginAllowedToUseIdty<T::Origin, T::IdtyIndex>
+    for Pallet<T>
+{
+    fn is_origin_allowed_to_use_idty(
+        origin: &T::Origin,
+        idty_index: &T::IdtyIndex,
+    ) -> sp_membership::OriginPermission {
+        match origin.clone().into() {
+            Ok(RawOrigin::Root) => sp_membership::OriginPermission::Root,
+            Ok(RawOrigin::Signed(account_id)) => {
+                if let Some(idty_val) = Pallet::<T>::identity(idty_index) {
+                    if account_id == idty_val.owner_key {
+                        sp_membership::OriginPermission::Allowed
+                    } else {
+                        sp_membership::OriginPermission::Forbidden
                     }
+                } else {
+                    sp_membership::OriginPermission::Forbidden
                 }
             }
+            _ => sp_membership::OriginPermission::Forbidden,
+        }
+    }
+}
 
-            total_weight
+impl<T: Config> sp_membership::traits::OnEvent<T::IdtyIndex> for Pallet<T> {
+    fn on_event(membership_event: sp_membership::Event<T::IdtyIndex>) -> Weight {
+        match membership_event {
+            sp_membership::Event::<T::IdtyIndex>::MembershipAcquired(_) => 0,
+            sp_membership::Event::<T::IdtyIndex>::MembershipExpired(idty_index) => {
+                Pallet::<T>::do_expire_identity(idty_index)
+            }
+            sp_membership::Event::<T::IdtyIndex>::MembershipRenewed(_) => 0,
+            sp_membership::Event::<T::IdtyIndex>::MembershipRequested(_) => 0,
+            sp_membership::Event::<T::IdtyIndex>::MembershipRevoked(_) => 0,
+            sp_membership::Event::<T::IdtyIndex>::PendingMembershipExpired(idty_index) => {
+                Pallet::<T>::do_remove_identity(idty_index)
+            }
         }
     }
 }
diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs
index d7b9ed028e0aae8c63bbf5b4af49e9eee143deb1..51e77fff10eb56665f9fe620b5aef0fef2a9b7f4 100644
--- a/pallets/identity/src/mock.rs
+++ b/pallets/identity/src/mock.rs
@@ -124,7 +124,7 @@ parameter_types! {
 pub struct IdtyNameValidatorTestImpl;
 impl pallet_identity::traits::IdtyNameValidator for IdtyNameValidatorTestImpl {
     fn validate(idty_name: &pallet_identity::IdtyName) -> bool {
-        idty_name.0.len() == 1
+        idty_name.0.len() < 16
     }
 }
 
@@ -143,10 +143,8 @@ impl pallet_identity::Config for Test {
     type IdtyRight = IdtyRight;
     type OnIdtyChange = ();
     type OnRightKeyChange = ();
-    type MaxInactivityPeriod = MaxInactivityPeriod;
     type MaxNoRightPeriod = MaxNoRightPeriod;
-    type RenewablePeriod = RenewablePeriod;
-    type ValidationPeriod = ValidationPeriod;
+    type Membership = ();
 }
 
 // Build genesis storage according to the mock runtime.
@@ -164,6 +162,7 @@ pub fn run_to_block(n: u64) {
     while System::block_number() < n {
         Identity::on_finalize(System::block_number());
         System::on_finalize(System::block_number());
+        System::reset_events();
         System::set_block_number(System::block_number() + 1);
         System::on_initialize(System::block_number());
         Identity::on_initialize(System::block_number());
diff --git a/pallets/identity/src/tests.rs b/pallets/identity/src/tests.rs
index 7b976305e0a9cfab16ea3501bdff334833ffd4a5..264b324c27088c4e643ef6aea9ceb9fe1aaaa374 100644
--- a/pallets/identity/src/tests.rs
+++ b/pallets/identity/src/tests.rs
@@ -16,45 +16,181 @@
 
 use crate::mock::IdtyRight as Right;
 use crate::mock::*;
-use crate::{Error, IdtyName};
+use crate::{Error, IdtyName, IdtyValue};
 use frame_support::assert_err;
 use frame_support::assert_ok;
 use frame_system::{EventRecord, Phase};
 
+type IdtyVal = IdtyValue<u64, u64, (), Right>;
+
+fn alice() -> IdtyVal {
+    IdtyVal {
+        data: (),
+        owner_key: 1,
+        name: IdtyName::from("Alice"),
+        next_creatable_identity_on: 0,
+        removable_on: 0,
+        rights: vec![(Right::Right1, None)],
+        status: crate::IdtyStatus::Validated,
+    }
+}
+fn bob() -> IdtyVal {
+    IdtyVal {
+        data: (),
+        owner_key: 2,
+        name: IdtyName::from("Bob"),
+        next_creatable_identity_on: 0,
+        removable_on: 0,
+        rights: vec![(Right::Right2, Some(20))],
+        status: crate::IdtyStatus::Validated,
+    }
+}
+
 #[test]
 fn test_no_identity() {
-    let identities = Vec::with_capacity(0);
-    new_test_ext(IdentityConfig { identities }).execute_with(|| {
+    new_test_ext(IdentityConfig {
+        identities: Vec::with_capacity(0),
+    })
+    .execute_with(|| {
         assert_eq!(Identity::identities_count(), 0);
     });
 }
 
+#[test]
+fn test_creator_not_exist() {
+    new_test_ext(IdentityConfig {
+        identities: Vec::with_capacity(0),
+    })
+    .execute_with(|| {
+        assert_eq!(
+            Identity::create_identity(Origin::signed(1), 1, IdtyName::from("bob"), 2),
+            Err(Error::<Test>::CreatorNotExist.into())
+        );
+    });
+}
+
+#[test]
+fn test_creator_not_have_right_to_create_identity() {
+    new_test_ext(IdentityConfig {
+        identities: vec![bob()],
+    })
+    .execute_with(|| {
+        // We need to initialize at least one block before any call
+        run_to_block(1);
+
+        // Bob not have right to create identities
+        assert_eq!(
+            Identity::create_identity(Origin::signed(2), 1, IdtyName::from("Charlie"), 3),
+            Err(Error::<Test>::CreatorNotHaveRightToCreateIdty.into())
+        );
+    })
+}
+
+#[test]
+fn test_creator_not_owner() {
+    new_test_ext(IdentityConfig {
+        identities: vec![alice()],
+    })
+    .execute_with(|| {
+        // We need to initialize at least one block before any call
+        run_to_block(1);
+
+        // Someone try to create an identity pretending to be Alice
+        assert_eq!(
+            Identity::create_identity(Origin::signed(2), 1, IdtyName::from("Charlie"), 3),
+            Err(Error::<Test>::RequireToBeOwner.into())
+        );
+    })
+}
+
+#[test]
+fn test_create_identity_ok() {
+    new_test_ext(IdentityConfig {
+        identities: vec![alice()],
+    })
+    .execute_with(|| {
+        // We need to initialize at least one block before any call
+        run_to_block(1);
+
+        // Alice should be able te create an identity
+        assert_ok!(Identity::create_identity(
+            Origin::signed(1),
+            1,
+            IdtyName::from("bob"),
+            2
+        ));
+        let events = System::events();
+        assert_eq!(events.len(), 1);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(crate::Event::IdtyCreated(IdtyName::from("bob"), 2)),
+                topics: vec![],
+            }
+        );
+    });
+}
+
+#[test]
+fn test_idty_creation_period() {
+    new_test_ext(IdentityConfig {
+        identities: vec![alice()],
+    })
+    .execute_with(|| {
+        // We need to initialize at least one block before any call
+        run_to_block(1);
+
+        // Alice should be able te create an identity
+        assert_ok!(Identity::create_identity(
+            Origin::signed(1),
+            1,
+            IdtyName::from("bob"),
+            2
+        ));
+        let events = System::events();
+        assert_eq!(events.len(), 1);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(crate::Event::IdtyCreated(IdtyName::from("bob"), 2)),
+                topics: vec![],
+            }
+        );
+        assert_eq!(Identity::identity(1).unwrap().next_creatable_identity_on, 4);
+
+        // Alice cannot create a new identity before block #4
+        run_to_block(2);
+        assert_eq!(
+            Identity::create_identity(Origin::signed(1), 1, IdtyName::from("Charlie"), 3),
+            Err(Error::<Test>::NotRespectIdtyCreationPeriod.into())
+        );
+
+        // Alice should be able te create a second identity after block #4
+        run_to_block(4);
+        assert_ok!(Identity::create_identity(
+            Origin::signed(1),
+            1,
+            IdtyName::from("Charlie"),
+            3
+        ));
+        let events = System::events();
+        assert_eq!(events.len(), 1);
+        assert_eq!(
+            events[0],
+            EventRecord {
+                phase: Phase::Initialization,
+                event: Event::Identity(crate::Event::IdtyCreated(IdtyName::from("Charlie"), 3)),
+                topics: vec![],
+            }
+        );
+    });
+}
+
 #[test]
 fn test_two_identities() {
-    let identities = vec![
-        crate::IdtyValue {
-            data: (),
-            expire_on: 5,
-            owner_key: 1,
-            name: IdtyName(vec![0]),
-            next_creatable_identity_on: 0,
-            removable_on: 0,
-            renewable_on: 3,
-            rights: vec![(Right::Right2, Some(10))],
-            status: crate::IdtyStatus::Validated,
-        },
-        crate::IdtyValue {
-            data: (),
-            expire_on: 5,
-            owner_key: 2,
-            name: IdtyName(vec![1]),
-            next_creatable_identity_on: 0,
-            removable_on: 0,
-            renewable_on: 3,
-            rights: vec![(Right::Right1, Some(20))],
-            status: crate::IdtyStatus::Validated,
-        },
-    ];
+    let identities = vec![alice(), bob()];
 
     new_test_ext(IdentityConfig { identities }).execute_with(|| {
         // Should have two identities
@@ -63,9 +199,15 @@ fn test_two_identities() {
         // We need to initialize at least one block before any call
         run_to_block(1);
 
-        // Add right Right1 for IdtyName(vec![0])
+        // Add right Right1 for Alice
+        // Should fail because Alice already have this right
+        assert_err!(
+            Identity::add_right(Origin::root(), 1, Right::Right1),
+            Error::<Test>::RightAlreadyAdded
+        );
+        // Add right Right2 for alice
         // Should succes and trigger the correct event
-        assert_ok!(Identity::add_right(Origin::root(), 1, Right::Right1));
+        assert_ok!(Identity::add_right(Origin::root(), 1, Right::Right2));
         let events = System::events();
         assert_eq!(events.len(), 1);
         assert_eq!(
@@ -73,39 +215,33 @@ fn test_two_identities() {
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(crate::Event::IdtyAcquireRight(
-                    IdtyName(vec![0]),
-                    Right::Right1
+                    IdtyName::from("Alice"),
+                    Right::Right2
                 )),
                 topics: vec![],
             }
         );
-        // Add right Right2 for IdtyName(vec![0])
-        // Should fail because IdtyName(vec![0]) already have this right
-        assert_err!(
-            Identity::add_right(Origin::root(), 1, Right::Right2),
-            Error::<Test>::RightAlreadyAdded
-        );
 
         run_to_block(3);
 
-        // Delete right Right1 for IdtyName(vec![1])
+        // Delete right Right2 for Bob
         // Should succes and trigger the correct event
-        assert_ok!(Identity::del_right(Origin::root(), 2, Right::Right1));
+        assert_ok!(Identity::del_right(Origin::root(), 2, Right::Right2));
         let events = System::events();
-        assert_eq!(events.len(), 2);
+        assert_eq!(events.len(), 1);
         assert_eq!(
-            events[1],
+            events[0],
             EventRecord {
                 phase: Phase::Initialization,
                 event: Event::Identity(crate::Event::IdtyLostRight(
-                    IdtyName(vec![1]),
-                    Right::Right1
+                    IdtyName::from("Bob"),
+                    Right::Right2
                 )),
                 topics: vec![],
             }
         );
 
-        // The IdtyName(vec![1]) identity has no more rights, the inactivity period must start to run
+        // The Bob identity has no more rights, the inactivity period must start to run
         let idty2 = Identity::identity(2).expect("idty not found");
         assert!(idty2.rights.is_empty());
         assert_eq!(idty2.removable_on, 7);
diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs
index caa9c2446b811c733bdd037c832e5b298f0b6e6d..d5b1e19b7b7383061c14f10669972ca5c92ef244 100644
--- a/pallets/identity/src/traits.rs
+++ b/pallets/identity/src/traits.rs
@@ -15,33 +15,17 @@
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
 use crate::*;
-use frame_support::{dispatch::DispatchError, pallet_prelude::*};
-use frame_system::pallet_prelude::*;
+use frame_support::pallet_prelude::*;
 use sp_runtime::traits::MaybeSerializeDeserialize;
 use sp_std::fmt::Debug;
 
 pub trait EnsureIdtyCallAllowed<T: Config> {
-    fn can_create_identity(
-        origin: T::Origin,
-        creator: T::IdtyIndex,
-        creator_idty: IdtyValue<T::AccountId, T::BlockNumber, T::IdtyData, T::IdtyRight>,
-        idty_name: &IdtyName,
-        idty_owner_key: &T::AccountId,
-    ) -> Result<(), DispatchError>;
+    fn can_create_identity(creator: T::IdtyIndex) -> bool;
 }
 
 impl<T: Config> EnsureIdtyCallAllowed<T> for () {
-    fn can_create_identity(
-        origin: T::Origin,
-        _creator: T::IdtyIndex,
-        _creator_idty: IdtyValue<T::AccountId, T::BlockNumber, T::IdtyData, T::IdtyRight>,
-        _idty_name: &IdtyName,
-        _idty_owner_key: &T::AccountId,
-    ) -> Result<(), DispatchError> {
-        match ensure_root(origin) {
-            Ok(()) => Ok(()),
-            Err(_) => Err(DispatchError::BadOrigin),
-        }
+    fn can_create_identity(_creator: T::IdtyIndex) -> bool {
+        true
     }
 }
 
diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs
index dcca75ea962926705929c001bd7d0abf353a363f..b4231157bae636c39221a8d7f7bd10c305c83912 100644
--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -80,12 +80,10 @@ pub struct IdtyValue<
     IdtyRight: Decode + Encode + TypeInfo,
 > {
     pub data: IdtyData,
-    pub expire_on: BlockNumber,
     pub owner_key: AccountId,
     pub name: IdtyName,
     pub next_creatable_identity_on: BlockNumber,
     pub removable_on: BlockNumber,
-    pub renewable_on: BlockNumber,
     pub rights: Vec<(IdtyRight, Option<AccountId>)>,
     pub status: IdtyStatus,
 }
diff --git a/pallets/membership/Cargo.toml b/pallets/membership/Cargo.toml
index 1b49766c4b4babe7a1b9776937a7b4f7228f1705..acdec3a966d9f66f580530b71683122e492bfd45 100644
--- a/pallets/membership/Cargo.toml
+++ b/pallets/membership/Cargo.toml
@@ -19,12 +19,14 @@ std = [
     'frame-benchmarking/std',
     'serde',
     'sp-core/std',
+    'sp-membership/std',
     'sp-runtime/std',
 	'sp-std/std',
 ]
 try-runtime = ['frame-support/try-runtime']
 
 [dependencies]
+sp-membership = { path = "../../primitives/membership", default-features = false }
 
 # substrate
 scale-info = { version = "1.0", default-features = false, features = ["derive"] }
diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs
index 951ad411c340fc5c0c5dd47e8563bc24ba8d7dbf..dd93b656e2555bd25dff794d838b72cbd6500eb1 100644
--- a/pallets/membership/src/lib.rs
+++ b/pallets/membership/src/lib.rs
@@ -17,9 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![allow(clippy::type_complexity)]
 
-pub mod traits;
-pub mod types;
-
 #[cfg(test)]
 mod mock;
 
@@ -31,10 +28,10 @@ mod benchmarking;*/
 
 pub use pallet::*;
 
-use crate::traits::*;
-use crate::types::{MembershipData, OriginPermission};
 use frame_support::dispatch::Weight;
 use frame_support::pallet_prelude::DispatchResultWithPostInfo;
+use sp_membership::traits::*;
+use sp_membership::{MembershipData, OriginPermission};
 use sp_runtime::traits::Zero;
 use sp_std::prelude::*;
 #[cfg(feature = "std")]
@@ -183,15 +180,17 @@ pub mod pallet {
     pub enum Error<T, I = ()> {
         /// Identity not allowed to claim membership
         IdtyNotAllowedToClaimMembership,
-        /// Identity not allowed to renew membership
-        IdtyNotAllowedToRenewMembership,
         /// Identity not allowed to request membership
         IdtyNotAllowedToRequestMembership,
-        /// Origin not allowed to use this identity
+        /// Identity not allowed to renew membership
+        IdtyNotAllowedToRenewMembership,
+        /// Membership already acquired
+        MembershipAlreadyAcquired,
         /// Membership not yet renewable
         MembershipNotYetRenewable,
         /// Membership not found
         MembershipNotFound,
+        /// Origin not allowed to use this identity
         OriginNotAllowedToUseIdty,
         /// Membership request not found
         MembershipRequestNotFound,
@@ -239,6 +238,9 @@ pub mod pallet {
             if !allowed {
                 return Err(Error::<T, I>::IdtyNotAllowedToRequestMembership.into());
             }
+            if Membership::<T, I>::contains_key(&idty_id) {
+                return Err(Error::<T, I>::MembershipAlreadyAcquired.into());
+            }
             if RevokedMembership::<T, I>::contains_key(&idty_id) {
                 return Err(Error::<T, I>::MembershipRevokedRecently.into());
             }
@@ -249,7 +251,7 @@ pub mod pallet {
             PendingMembership::<T, I>::insert(idty_id, ());
             PendingMembershipsExpireOn::<T, I>::append(expire_on, idty_id);
             Self::deposit_event(Event::MembershipRequested(idty_id));
-            T::OnEvent::on_event(crate::types::Event::MembershipRequested(idty_id));
+            T::OnEvent::on_event(sp_membership::Event::MembershipRequested(idty_id));
 
             Ok(().into())
         }
@@ -346,13 +348,13 @@ pub mod pallet {
             PendingMembership::<T, I>::remove(&idty_id);
             total_weight += Self::do_renew_membership_inner(idty_id);
             Self::deposit_event(Event::MembershipAcquired(idty_id));
-            T::OnEvent::on_event(crate::types::Event::MembershipAcquired(idty_id));
+            T::OnEvent::on_event(sp_membership::Event::MembershipAcquired(idty_id));
             total_weight
         }
         pub(super) fn do_renew_membership(idty_id: T::IdtyId) -> Weight {
             let total_weight = Self::do_renew_membership_inner(idty_id);
             Self::deposit_event(Event::MembershipRenewed(idty_id));
-            T::OnEvent::on_event(crate::types::Event::MembershipRenewed(idty_id));
+            T::OnEvent::on_event(sp_membership::Event::MembershipRenewed(idty_id));
             total_weight
         }
         fn do_renew_membership_inner(idty_id: T::IdtyId) -> Weight {
@@ -371,14 +373,17 @@ pub mod pallet {
             0
         }
         pub(super) fn do_revoke_membership(idty_id: T::IdtyId) -> Weight {
-            let block_number = frame_system::pallet::Pallet::<T>::block_number();
-            let pruned_on = block_number + T::RevocationPeriod::get();
-
             Self::remove_membership(&idty_id);
-            RevokedMembership::<T, I>::insert(idty_id, ());
-            RevokedMembershipsPrunedOn::<T, I>::append(pruned_on, idty_id);
+            if T::RevocationPeriod::get() > Zero::zero() {
+                let block_number = frame_system::pallet::Pallet::<T>::block_number();
+                let pruned_on = block_number + T::RevocationPeriod::get();
+
+                RevokedMembership::<T, I>::insert(idty_id, ());
+                RevokedMembershipsPrunedOn::<T, I>::append(pruned_on, idty_id);
+            }
             Self::deposit_event(Event::MembershipRevoked(idty_id));
-            T::OnEvent::on_event(crate::types::Event::MembershipRevoked(idty_id));
+            T::OnEvent::on_event(sp_membership::Event::MembershipRevoked(idty_id));
+
             0
         }
         fn expire_memberships(block_number: T::BlockNumber) -> Weight {
@@ -394,7 +399,7 @@ pub mod pallet {
                             Self::remove_membership(&idty_id);
                             Self::deposit_event(Event::MembershipExpired(idty_id));
                             total_weight += T::OnEvent::on_event(
-                                crate::types::Event::MembershipExpired(idty_id),
+                                sp_membership::Event::MembershipExpired(idty_id),
                             );
                         }
                     }
@@ -416,7 +421,7 @@ pub mod pallet {
                     PendingMembership::<T, I>::remove(&idty_id);
                     Self::deposit_event(Event::PendingMembershipExpired(idty_id));
                     total_weight += T::OnEvent::on_event(
-                        crate::types::Event::PendingMembershipExpired(idty_id),
+                        sp_membership::Event::PendingMembershipExpired(idty_id),
                     );
                 }
             }
diff --git a/pallets/membership/src/mock.rs b/pallets/membership/src/mock.rs
index 237d93a2794154501e2c06ab7d2aa9afe6d87703..3a9869bf0189d1d587b428b510181cbd043b8385 100644
--- a/pallets/membership/src/mock.rs
+++ b/pallets/membership/src/mock.rs
@@ -14,8 +14,6 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-use crate::traits::IsOriginAllowedToUseIdty;
-use crate::types::OriginPermission;
 use crate::{self as pallet_membership};
 use frame_support::{
     parameter_types,
@@ -23,6 +21,8 @@ use frame_support::{
 };
 use frame_system as system;
 use sp_core::H256;
+use sp_membership::traits::IsOriginAllowedToUseIdty;
+use sp_membership::OriginPermission;
 use sp_runtime::{
     testing::Header,
     traits::{BlakeTwo256, IdentityLookup},
diff --git a/pallets/membership/src/tests.rs b/pallets/membership/src/tests.rs
index f98e49909f25194f0fc3af5a6dee85eb21c086cb..0ac4522803238f4fc324c557ff2dad90e5a5f3a2 100644
--- a/pallets/membership/src/tests.rs
+++ b/pallets/membership/src/tests.rs
@@ -16,11 +16,11 @@
 
 use crate::mock::Event as RuntimeEvent;
 use crate::mock::*;
-use crate::traits::{IsInPendingMemberships, IsMember};
-use crate::types::MembershipData;
 use crate::{Error, Event};
 use frame_support::assert_ok;
 use maplit::btreemap;
+use sp_membership::traits::{IsInPendingMemberships, IsMember};
+use sp_membership::MembershipData;
 
 fn default_gen_conf() -> DefaultMembershipConfig {
     DefaultMembershipConfig {
diff --git a/primitives/membership/Cargo.toml b/primitives/membership/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..29bb6472df273c18669c41966745a521b9561f56
--- /dev/null
+++ b/primitives/membership/Cargo.toml
@@ -0,0 +1,51 @@
+[package]
+authors = ['librelois <c@elo.tf>']
+description = 'primitives for pallet membership.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'sp-membership'
+readme = 'README.md'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[features]
+default = ['std']
+std = [
+    'codec/std',
+    'frame-support/std',
+    'serde',
+	'sp-std/std',
+]
+try-runtime = ['frame-support/try-runtime']
+
+[dependencies]
+
+# substrate
+scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '2.3.1'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.serde]
+version = "1.0.101"
+optional = true
+features = ["derive"]
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/pallets/membership/src/types.rs b/primitives/membership/src/lib.rs
similarity index 91%
rename from pallets/membership/src/types.rs
rename to primitives/membership/src/lib.rs
index 5eac495064d28f0bfd3c7bacd9f169d3dfef0590..bae4cf2d8459ace2113225a6f6bff77a8aebb798 100644
--- a/pallets/membership/src/types.rs
+++ b/primitives/membership/src/lib.rs
@@ -14,7 +14,12 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-//! Various basic types for use in the membership pallet.
+//! Defines types and traits for users of pallet membership.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![allow(clippy::type_complexity)]
+
+pub mod traits;
 
 use codec::{Decode, Encode};
 use frame_support::RuntimeDebug;
@@ -24,22 +29,16 @@ use serde::{Deserialize, Serialize};
 
 pub enum Event<IdtyId> {
     /// A membership has acquired
-    /// [idty_id]
     MembershipAcquired(IdtyId),
     /// A membership has expired
-    /// [idty_id]
     MembershipExpired(IdtyId),
     /// A membership has renewed
-    /// [idty_id]
     MembershipRenewed(IdtyId),
     /// An identity requested membership
-    /// [idty_id]
     MembershipRequested(IdtyId),
     /// A membership has revoked
-    /// [idty_id]
     MembershipRevoked(IdtyId),
     /// A pending membership request has expired
-    /// [idty_id]
     PendingMembershipExpired(IdtyId),
 }
 
diff --git a/pallets/membership/src/traits.rs b/primitives/membership/src/traits.rs
similarity index 80%
rename from pallets/membership/src/traits.rs
rename to primitives/membership/src/traits.rs
index c0360b20157f2e9120a49a35d135349749269d7d..580eaa82e35fe0a356eacd0ad1cad54a0ab78a02 100644
--- a/pallets/membership/src/traits.rs
+++ b/primitives/membership/src/traits.rs
@@ -14,9 +14,8 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-use crate::types::OriginPermission;
 use crate::*;
-use frame_support::pallet_prelude::DispatchResultWithPostInfo;
+use frame_support::pallet_prelude::{DispatchResultWithPostInfo, TypeInfo, Weight};
 
 pub trait IsIdtyAllowedToClaimMembership<IdtyId> {
     fn is_idty_allowed_to_claim_membership(idty_id: &IdtyId) -> bool;
@@ -73,11 +72,11 @@ impl<IdtyId> IsMember<IdtyId> for () {
 }
 
 pub trait OnEvent<IdtyId> {
-    fn on_event(event: crate::types::Event<IdtyId>) -> Weight;
+    fn on_event(event: crate::Event<IdtyId>) -> Weight;
 }
 
 impl<IdtyId> OnEvent<IdtyId> for () {
-    fn on_event(_: crate::types::Event<IdtyId>) -> Weight {
+    fn on_event(_: crate::Event<IdtyId>) -> Weight {
         0
     }
 }
@@ -92,6 +91,30 @@ pub trait MembershipAction<IdtyId, Origin> {
     fn force_revoke_membership(idty_id: IdtyId) -> Weight;
 }
 
+impl<IdtyId, Origin> MembershipAction<IdtyId, Origin> for () {
+    fn request_membership_(_: Origin, _: IdtyId) -> DispatchResultWithPostInfo {
+        Ok(().into())
+    }
+    fn claim_membership_(_: Origin, _: IdtyId) -> DispatchResultWithPostInfo {
+        Ok(().into())
+    }
+    fn renew_membership_(_: Origin, _: IdtyId) -> DispatchResultWithPostInfo {
+        Ok(().into())
+    }
+    fn revoke_membership_(_: Origin, _: IdtyId) -> DispatchResultWithPostInfo {
+        Ok(().into())
+    }
+    fn force_claim_membership(_: IdtyId) -> Weight {
+        0
+    }
+    fn force_renew_membership(_: IdtyId) -> Weight {
+        0
+    }
+    fn force_revoke_membership(_: IdtyId) -> Weight {
+        0
+    }
+}
+
 pub trait MembershipExternalStorage<BlockNumber: Decode + Encode + TypeInfo, IdtyId>:
     IsMember<IdtyId>
 {
@@ -100,8 +123,6 @@ pub trait MembershipExternalStorage<BlockNumber: Decode + Encode + TypeInfo, Idt
     fn remove(idty_id: &IdtyId);
 }
 
-use codec::{Decode, Encode};
-use frame_support::pallet_prelude::TypeInfo;
 static INVALID_CONF_MSG: &str = "invalid pallet configuration: if `MembershipExternalStorage` = (), you must set `ExternalizeMembershipStorage` to `false`.";
 
 impl<BlockNumber: Decode + Encode + TypeInfo, IdtyId> MembershipExternalStorage<BlockNumber, IdtyId>
diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml
index 998747927a1ce6570868db344e3d7beac1d04c13..c1ba7a8676754fe6dac3cd2da4ce2ee738f12335 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -12,6 +12,7 @@ runtime-benchmarks = [
     'frame-system/runtime-benchmarks',
     'pallet-certification/runtime-benchmarks',
     'pallet-identity/runtime-benchmarks',
+    'pallet-membership/runtime-benchmarks',
     'pallet-ud-accounts-storage/runtime-benchmarks',
     'sp-runtime/runtime-benchmarks',
 ]
@@ -21,6 +22,7 @@ std = [
     'frame-system/std',
     'pallet-certification/std',
     'pallet-identity/std',
+    'pallet-membership/std',
     'pallet-ud-accounts-storage/std',
     'serde',
     'sp-arithmetic/std',
@@ -32,6 +34,7 @@ std = [
 [dependencies]
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
+pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 smallvec = "1.6.1"
 
diff --git a/runtime/common/src/authorizations.rs b/runtime/common/src/authorizations.rs
index 1c2ef413e85715ab5ed204c81a5219206ed246a8..d5be8c5a9eea64bec9ffe5ff7bea43ea8acc1233 100644
--- a/runtime/common/src/authorizations.rs
+++ b/runtime/common/src/authorizations.rs
@@ -14,9 +14,8 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-use crate::entities::{IdtyData, IdtyRight};
+use crate::entities::IdtyRight;
 use crate::{BlockNumber, IdtyIndex};
-use frame_support::pallet_prelude::DispatchError;
 use frame_support::traits::EnsureOrigin;
 use pallet_certification::traits::IsIdtyAllowedToCreateCert;
 use pallet_identity::IdtyStatus;
@@ -26,57 +25,13 @@ pub struct EnsureIdtyCallAllowedImpl<Runtime, IsIdtyAllowedToCreateCertImpl>(
 );
 impl<
         Runtime: frame_system::Config<BlockNumber = BlockNumber>
-            + pallet_identity::Config<
-                IdtyData = IdtyData,
-                IdtyIndex = IdtyIndex,
-                IdtyRight = IdtyRight,
-            >,
+            + pallet_identity::Config<IdtyIndex = IdtyIndex>,
         IsIdtyAllowedToCreateCertImpl: IsIdtyAllowedToCreateCert<IdtyIndex>,
     > pallet_identity::traits::EnsureIdtyCallAllowed<Runtime>
     for EnsureIdtyCallAllowedImpl<Runtime, IsIdtyAllowedToCreateCertImpl>
 {
-    fn can_create_identity(
-        origin: Runtime::Origin,
-        creator: IdtyIndex,
-        creator_idty: pallet_identity::IdtyValue<
-            Runtime::AccountId,
-            BlockNumber,
-            IdtyData,
-            IdtyRight,
-        >,
-        _idty_name: &pallet_identity::IdtyName,
-        _idty_owner_key: &Runtime::AccountId,
-    ) -> Result<(), DispatchError> {
-        match origin.into() {
-            Ok(frame_system::RawOrigin::Root) => Ok(()),
-            Ok(frame_system::RawOrigin::Signed(signer)) => {
-                if let Some(authorized_key) = creator_idty.get_right_key(IdtyRight::CreateIdty) {
-                    if signer != authorized_key {
-                        frame_support::runtime_print!("signer != authorized_key");
-                        Err(DispatchError::Other("signer != authorized_key"))
-                    } else if !IsIdtyAllowedToCreateCertImpl::is_idty_allowed_to_create_cert(
-                        creator,
-                    ) {
-                        frame_support::runtime_print!("not allowed to create cert");
-                        Err(DispatchError::Other("not allowed to create cert"))
-                    } else if creator_idty.data.can_create_on
-                        > frame_system::Pallet::<Runtime>::block_number()
-                    {
-                        frame_support::runtime_print!("Not respect IdtyCreatePeriod");
-                        Err(DispatchError::Other("Not respect IdtyCreatePeriod"))
-                    } else {
-                        Ok(())
-                    }
-                } else {
-                    frame_support::runtime_print!("Idty not have right CreateIdty");
-                    Err(DispatchError::Other("Idty not have right CreateIdty"))
-                }
-            }
-            _ => {
-                frame_support::runtime_print!("Origin neither root or signed");
-                Err(DispatchError::Other("Origin neither root or signed"))
-            }
-        }
+    fn can_create_identity(creator: IdtyIndex) -> bool {
+        IsIdtyAllowedToCreateCertImpl::is_idty_allowed_to_create_cert(creator)
     }
 }
 
diff --git a/runtime/common/src/entities.rs b/runtime/common/src/entities.rs
index a61f165199b97188b150cebb32238398df484adc..0943cd78f6703da376afa3e6cb23f3fcf5181501 100644
--- a/runtime/common/src/entities.rs
+++ b/runtime/common/src/entities.rs
@@ -16,7 +16,6 @@
 
 pub use pallet_identity::IdtyName;
 
-use crate::BlockNumber;
 use frame_support::pallet_prelude::*;
 use scale_info::TypeInfo;
 #[cfg(feature = "std")]
@@ -48,12 +47,6 @@ impl pallet_identity::traits::IdtyRight for IdtyRight {
     }
 }
 
-#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
-#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-pub struct IdtyData {
-    pub can_create_on: BlockNumber,
-}
-
 #[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
 #[derive(
     Encode, Decode, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo,
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index 3bb3e44fd4f473ca89e482368483732d0859d0fb..7113df7e006c9b73a6848e2ae8cb93efc235c686 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -191,20 +191,34 @@ macro_rules! pallets_config {
             type DelRightOrigin = EnsureRoot<Self::AccountId>;
             type EnsureIdtyCallAllowed = EnsureIdtyCallAllowedImpl<Runtime, StrongCert>;
 			type IdtyCreationPeriod = IdtyCreationPeriod;
-			type IdtyDataProvider = IdtyDataProvider<Runtime, IDTY_CREATE_PERIOD>;
-            type IdtyData = IdtyData;
+			type IdtyDataProvider = ();
+            type IdtyData = ();
             type IdtyNameValidator = IdtyNameValidatorImpl;
             type IdtyIndex = IdtyIndex;
             type IdtyValidationOrigin = EnsureRoot<Self::AccountId>;
             type IdtyRight = IdtyRight;
             type OnIdtyChange = OnIdtyChangeHandler<Runtime>;
             type OnRightKeyChange = OnRightKeyChangeHandler<Runtime>;
-            type MaxInactivityPeriod = MaxInactivityPeriod;
             type MaxNoRightPeriod = MaxNoRightPeriod;
-            type RenewablePeriod = IdtyRenewablePeriod;
-            type ValidationPeriod = ValidationPeriod;
+			type Membership = Membership;
         }
 
+		impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {
+			type IsIdtyAllowedToClaimMembership = ();
+			type IsIdtyAllowedToRenewMembership = ();
+			type IsIdtyAllowedToRequestMembership = ();
+			type IsOriginAllowedToUseIdty = Identity;
+			type Event = Event;
+			type ExternalizeMembershipStorage = frame_support::traits::ConstBool<false>;
+			type IdtyId = IdtyIndex;
+			type OnEvent = Identity;
+			type MembershipExternalStorage = ();
+			type MembershipPeriod = MembershipPeriod;
+			type PendingMembershipPeriod = PendingMembershipPeriod;
+			type RenewablePeriod = RenewablePeriod;
+			type RevocationPeriod = frame_support::traits::ConstU32<0>;
+		}
+
         impl pallet_certification::Config<frame_support::instances::Instance1> for Runtime {
             type AddCertOrigin = AddStrongCertOrigin<Runtime>;
             type CertPeriod = CertPeriod;
diff --git a/runtime/common/src/providers.rs b/runtime/common/src/providers.rs
index a48d9782e4d7af6349c952d6810ce093eb4791ea..1f49810e9455fefa28402692790c9259812d7f49 100644
--- a/runtime/common/src/providers.rs
+++ b/runtime/common/src/providers.rs
@@ -14,35 +14,10 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
 
-use crate::entities::IdtyData;
-use crate::{AccountId, BlockNumber, IdtyIndex};
+use crate::AccountId;
 use frame_support::traits::Get;
 use sp_std::vec::Vec;
 
-pub struct IdtyDataProvider<Runtime, const IDTY_CREATE_PERIOD: BlockNumber>(
-    core::marker::PhantomData<Runtime>,
-);
-impl<Runtime, const IDTY_CREATE_PERIOD: BlockNumber>
-    pallet_identity::traits::ProvideIdtyData<Runtime>
-    for IdtyDataProvider<Runtime, IDTY_CREATE_PERIOD>
-where
-    Runtime: frame_system::Config<AccountId = AccountId, BlockNumber = BlockNumber>
-        + pallet_identity::Config<IdtyData = IdtyData, IdtyIndex = IdtyIndex>,
-{
-    fn provide_identity_data(
-        creator: IdtyIndex,
-        _idty_name: &pallet_identity::IdtyName,
-        _idty_owner_key: &AccountId,
-    ) -> IdtyData {
-        let block_number = frame_system::Pallet::<Runtime>::block_number();
-        let creator_idty_data = IdtyData {
-            can_create_on: block_number + IDTY_CREATE_PERIOD,
-        };
-        pallet_identity::Pallet::<Runtime>::set_idty_data(creator, creator_idty_data);
-        Default::default()
-    }
-}
-
 pub struct UdAccountsProvider<Runtime>(core::marker::PhantomData<Runtime>);
 impl<Runtime: pallet_ud_accounts_storage::Config> Get<u64> for UdAccountsProvider<Runtime> {
     fn get() -> u64 {
diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml
index 6046607d31e72ac7cbffde8a15cea9e3a2a5825a..53fe0a7647f8fa129bf36310a21f8fdc303e1aec 100644
--- a/runtime/g1/Cargo.toml
+++ b/runtime/g1/Cargo.toml
@@ -39,6 +39,7 @@ std = [
     'pallet-grandpa/std',
     'pallet-identity/std',
     'pallet-im-online/std',
+    'pallet-membership/std',
     'pallet-multisig/std',
     'pallet-session/std',
     'pallet-sudo/std',
@@ -67,6 +68,7 @@ std = [
 [dependencies]
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
+pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 common-runtime = { path = "../common", default-features = false }
diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs
index 5a1a9024cbe2a345276030e8b330f09814f74a19..6d5d6ec90c2addd7a304ea7d8e48766dfad223bd 100644
--- a/runtime/g1/src/lib.rs
+++ b/runtime/g1/src/lib.rs
@@ -27,7 +27,7 @@ pub mod parameters;
 pub use self::parameters::*;
 pub use common_runtime::{
     constants::*,
-    entities::{IdtyData, IdtyRight, ValidatorFullIdentification},
+    entities::{IdtyRight, ValidatorFullIdentification},
     AccountId, Address, Balance, BlockNumber, FullIdentificationOfImpl, Hash, Header, IdtyIndex,
     IdtyNameValidatorImpl, Index, Signature,
 };
@@ -48,7 +48,6 @@ use common_runtime::{
         OnIdtyChangeHandler, OnNewStrongCertHandler, OnRemovedStrongCertHandler,
         OnRightKeyChangeHandler,
     },
-    providers::IdtyDataProvider,
     SessionManagerImpl,
 };
 use frame_system::EnsureRoot;
@@ -189,7 +188,8 @@ construct_runtime!(
 
         // Web Of Trust
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 50,
-        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
 
         // Multisig dispatch.
         Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 60,
diff --git a/runtime/g1/src/parameters.rs b/runtime/g1/src/parameters.rs
index 2a1eea4d603c738bf5a414fe8847b43737bfe8de..5e334ce48cf1c1f04afbde88e25d7dba2dc6c7d3 100644
--- a/runtime/g1/src/parameters.rs
+++ b/runtime/g1/src/parameters.rs
@@ -94,16 +94,21 @@ parameter_types! {
 
 // Identity
 pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
-frame_support::parameter_types! {
+parameter_types! {
     pub const ConfirmPeriod: BlockNumber = 14 * DAYS;
     pub const FirstIssuableOn: BlockNumber = 30* DAYS;
     pub const IdtyCreationPeriod: BlockNumber = MONTHS;
-    pub const IdtyRenewablePeriod: BlockNumber = 6 * MONTHS;
-    pub const MaxInactivityPeriod: BlockNumber = YEARS;
     pub const MaxNoRightPeriod: BlockNumber = YEARS;
     pub const ValidationPeriod: BlockNumber = YEARS;
 }
 
+// Membership
+parameter_types! {
+    pub const MembershipPeriod: BlockNumber = YEARS;
+    pub const PendingMembershipPeriod: BlockNumber = 2 * MONTHS;
+    pub const RenewablePeriod: BlockNumber = 2 * MONTHS;
+}
+
 // Certification
 pub const MIN_STRONG_CERT_FOR_UD: u32 = 5;
 pub const MIN_STRONG_CERT_FOR_STRONG_CERT: u32 = 5;
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index d8d6ce509e25a1364669b0fde09cb261251b51b3..0578b60d7dd22b8195ab74da1ed56bc50b00efde 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -37,6 +37,7 @@ std = [
     'pallet-balances/std',
     'pallet-certification/std',
     'pallet-identity/std',
+    'pallet-membership/std',
     'pallet-grandpa/std',
     'pallet-multisig/std',
     'pallet-sudo/std',
@@ -63,6 +64,7 @@ std = [
 [dependencies]
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
+pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 common-runtime = { path = "../common", default-features = false }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index e450fb271b12ebb628fa6622b5932ecfbd820318..a804a418796abe6e9b56663a9738a471b90253af 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -26,10 +26,8 @@ pub mod parameters;
 
 pub use self::parameters::*;
 pub use common_runtime::{
-    constants::*,
-    entities::{IdtyData, IdtyRight},
-    AccountId, Address, Balance, BlockNumber, Hash, Header, IdtyIndex, IdtyNameValidatorImpl,
-    Index, Signature,
+    constants::*, entities::IdtyRight, AccountId, Address, Balance, BlockNumber, Hash, Header,
+    IdtyIndex, IdtyNameValidatorImpl, Index, Signature,
 };
 pub use pallet_balances::Call as BalancesCall;
 pub use pallet_identity::{IdtyStatus, IdtyValue};
@@ -45,7 +43,6 @@ use common_runtime::{
         OnIdtyChangeHandler, OnNewStrongCertHandler, OnRemovedStrongCertHandler,
         OnRightKeyChangeHandler,
     },
-    providers::IdtyDataProvider,
 };
 use frame_system::EnsureRoot;
 use pallet_grandpa::fg_primitives;
@@ -172,7 +169,8 @@ construct_runtime!(
 
         // Web Of Trust
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 50,
-        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
 
         // Multisig dispatch.
         Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 60,
diff --git a/runtime/gdev/src/parameters.rs b/runtime/gdev/src/parameters.rs
index e51875d38cb65d46c4c061f85db72302d8e89080..b6a1697f9c24855547805acb35a0b1ad3bf5607e 100644
--- a/runtime/gdev/src/parameters.rs
+++ b/runtime/gdev/src/parameters.rs
@@ -52,10 +52,14 @@ frame_support::parameter_types! {
     pub const ConfirmPeriod: BlockNumber = 40;
     pub const FirstIssuableOn: BlockNumber = 20;
     pub const IdtyCreationPeriod: BlockNumber = 50;
-    pub const IdtyRenewablePeriod: BlockNumber = 50;
-    pub const MaxInactivityPeriod: BlockNumber = 1_000;
     pub const MaxNoRightPeriod: BlockNumber = 1_000;
-    pub const ValidationPeriod: BlockNumber = 500;
+}
+
+// Membership
+parameter_types! {
+    pub const MembershipPeriod: BlockNumber = 1_000;
+    pub const PendingMembershipPeriod: BlockNumber = 500;
+    pub const RenewablePeriod: BlockNumber = 50;
 }
 
 // Certification
diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml
index 707a56c0a790663c15b15782ca358b3ebb584b23..3109fb572b38e0ff790ab75ca222143679c22977 100644
--- a/runtime/gtest/Cargo.toml
+++ b/runtime/gtest/Cargo.toml
@@ -38,6 +38,7 @@ std = [
     'pallet-certification/std',
     'pallet-grandpa/std',
     'pallet-identity/std',
+    'pallet-membership/std',
     'pallet-im-online/std',
     'pallet-multisig/std',
     'pallet-session/std',
@@ -67,6 +68,7 @@ std = [
 [dependencies]
 pallet-certification = { path = '../../pallets/certification', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
+pallet-membership = { path = '../../pallets/membership', default-features = false }
 pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false }
 pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false }
 common-runtime = { path = "../common", default-features = false }
diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs
index d3b0d711e3382f068b82a0ab582200423ca07556..e838a8127906b0e189a46e92c84600a6e2d0dace 100644
--- a/runtime/gtest/src/lib.rs
+++ b/runtime/gtest/src/lib.rs
@@ -27,7 +27,7 @@ pub mod parameters;
 pub use self::parameters::*;
 pub use common_runtime::{
     constants::*,
-    entities::{IdtyData, IdtyRight, ValidatorFullIdentification},
+    entities::{IdtyRight, ValidatorFullIdentification},
     AccountId, Address, Balance, BlockNumber, FullIdentificationOfImpl, Hash, Header, IdtyIndex,
     IdtyNameValidatorImpl, Index, Signature,
 };
@@ -48,7 +48,6 @@ use common_runtime::{
         OnIdtyChangeHandler, OnNewStrongCertHandler, OnRemovedStrongCertHandler,
         OnRightKeyChangeHandler,
     },
-    providers::IdtyDataProvider,
     SessionManagerImpl,
 };
 use frame_system::EnsureRoot;
@@ -189,7 +188,8 @@ construct_runtime!(
 
         // Web Of Trust
         Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 50,
-        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 51,
+        StrongCert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52,
 
         // Multisig dispatch.
         Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 60,
diff --git a/runtime/gtest/src/parameters.rs b/runtime/gtest/src/parameters.rs
index 44f287dfde8ef904b62b7c55c8f459b18eb9f7b3..ed4ca96bd7472e4511d8bb33f5350d7758377f65 100644
--- a/runtime/gtest/src/parameters.rs
+++ b/runtime/gtest/src/parameters.rs
@@ -97,10 +97,14 @@ frame_support::parameter_types! {
     pub const ConfirmPeriod: BlockNumber = 8 * HOURS;
     pub const FirstIssuableOn: BlockNumber = DAYS;
     pub const IdtyCreationPeriod: BlockNumber = DAYS;
-    pub const IdtyRenewablePeriod: BlockNumber = 12 * DAYS;
-    pub const MaxInactivityPeriod: BlockNumber = 73 * DAYS;
     pub const MaxNoRightPeriod: BlockNumber = 73 * DAYS;
-    pub const ValidationPeriod: BlockNumber = 73 * DAYS;
+}
+
+// Membership
+parameter_types! {
+    pub const MembershipPeriod: BlockNumber = 73 * DAYS;
+    pub const PendingMembershipPeriod: BlockNumber = 12 * DAYS;
+    pub const RenewablePeriod: BlockNumber = 12 * DAYS;
 }
 
 // Certification