diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 1416e9855234..7b7a59bc8660 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -57,18 +57,18 @@ pub struct ProfileDefaultRoutingConfig { pub connectors: Vec, } -#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct RoutingRetrieveQuery { pub limit: Option, pub offset: Option, } -#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct RoutingRetrieveLinkQuery { pub profile_id: Option, } -#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct RoutingRetrieveLinkQueryWrapper { pub routing_query: RoutingRetrieveQuery, pub profile_id: common_utils::id_type::ProfileId, diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 512f97b8c9e2..9efe2cd6ab29 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -84,12 +84,13 @@ impl RoutingAlgorithmUpdate { pub async fn retrieve_merchant_routing_dictionary( state: SessionState, merchant_account: domain::MerchantAccount, + profile_id_list: Option>, query_params: RoutingRetrieveQuery, transaction_type: &enums::TransactionType, ) -> RouterResponse { metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE.add(&metrics::CONTEXT, 1, &[]); - let routing_metadata = state + let routing_metadata: Vec = state .store .list_routing_algorithm_metadata_by_merchant_id_transaction_type( merchant_account.get_id(), @@ -99,6 +100,9 @@ pub async fn retrieve_merchant_routing_dictionary( ) .await .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; + let routing_metadata = + super::utils::filter_objects_based_on_profile_id_list(profile_id_list, routing_metadata); + let result = routing_metadata .into_iter() .map(ForeignInto::foreign_into) @@ -115,6 +119,7 @@ pub async fn create_routing_algorithm_under_profile( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, + authentication_profile_id: Option, request: routing_types::RoutingConfigRequest, transaction_type: &enums::TransactionType, ) -> RouterResponse { @@ -132,6 +137,8 @@ pub async fn create_routing_algorithm_under_profile( .await? .get_required_value("BusinessProfile")?; + core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?; + let all_mcas = helpers::MerchantConnectorAccounts::get_all_mcas( merchant_account.get_id(), &key_store, @@ -182,6 +189,7 @@ pub async fn create_routing_algorithm_under_profile( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, + authentication_profile_id: Option, request: routing_types::RoutingConfigRequest, transaction_type: &enums::TransactionType, ) -> RouterResponse { @@ -221,14 +229,17 @@ pub async fn create_routing_algorithm_under_profile( }) .attach_printable("Profile_id not provided")?; - core_utils::validate_and_get_business_profile( + let business_profile = core_utils::validate_and_get_business_profile( db, key_manager_state, &key_store, Some(&profile_id), merchant_account.get_id(), ) - .await?; + .await? + .get_required_value("BusinessProfile")?; + + core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?; helpers::validate_connectors_in_routing_config( &state, @@ -345,6 +356,7 @@ pub async fn link_routing_config( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, + authentication_profile_id: Option, algorithm_id: common_utils::id_type::RoutingId, transaction_type: &enums::TransactionType, ) -> RouterResponse { @@ -373,6 +385,8 @@ pub async fn link_routing_config( id: routing_algorithm.profile_id.get_string_repr().to_owned(), })?; + core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?; + let mut routing_ref: routing_types::RoutingAlgorithmRef = business_profile .routing_algorithm .clone() @@ -421,6 +435,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, + authentication_profile_id: Option, algorithm_id: common_utils::id_type::RoutingId, ) -> RouterResponse { metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]); @@ -430,7 +445,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( let routing_algorithm = RoutingAlgorithmUpdate::fetch_routing_algo(merchant_account.get_id(), &algorithm_id, db) .await?; - core_utils::validate_and_get_business_profile( + let business_profile = core_utils::validate_and_get_business_profile( db, key_manager_state, &key_store, @@ -441,6 +456,8 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( .get_required_value("BusinessProfile") .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?; + core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?; + let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm.0) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to parse routing algorithm")?; @@ -454,6 +471,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, + authentication_profile_id: Option, algorithm_id: common_utils::id_type::RoutingId, ) -> RouterResponse { metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]); @@ -468,7 +486,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( .await .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; - core_utils::validate_and_get_business_profile( + let business_profile = core_utils::validate_and_get_business_profile( db, key_manager_state, &key_store, @@ -479,6 +497,8 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( .get_required_value("BusinessProfile") .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?; + core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?; + let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to parse routing algorithm")?; @@ -554,9 +574,11 @@ pub async fn unlink_routing_config( merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, request: routing_types::RoutingConfigRequest, + authentication_profile_id: Option, transaction_type: &enums::TransactionType, ) -> RouterResponse { metrics::ROUTING_UNLINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -567,6 +589,7 @@ pub async fn unlink_routing_config( field_name: "profile_id", }) .attach_printable("Profile_id not provided")?; + let business_profile = core_utils::validate_and_get_business_profile( db, key_manager_state, @@ -575,8 +598,13 @@ pub async fn unlink_routing_config( merchant_account.get_id(), ) .await?; + match business_profile { Some(business_profile) => { + core_utils::validate_profile_id_from_auth_layer( + authentication_profile_id, + &business_profile, + )?; let routing_algo_ref: routing_types::RoutingAlgorithmRef = match transaction_type { enums::TransactionType::Payment => business_profile.routing_algorithm.clone(), #[cfg(feature = "payouts")] @@ -880,6 +908,7 @@ pub async fn retrieve_linked_routing_config( state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, + authentication_profile_id: Option, query_params: routing_types::RoutingRetrieveLinkQuery, transaction_type: &enums::TransactionType, ) -> RouterResponse { @@ -902,13 +931,18 @@ pub async fn retrieve_linked_routing_config( id: profile_id.get_string_repr().to_owned(), })? } else { - db.list_business_profile_by_merchant_id( - key_manager_state, - &key_store, - merchant_account.get_id(), + let business_profile = db + .list_business_profile_by_merchant_id( + key_manager_state, + &key_store, + merchant_account.get_id(), + ) + .await + .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; + core_utils::filter_objects_based_on_profile_id_list( + authentication_profile_id.map(|profile_id| vec![profile_id]), + business_profile.clone(), ) - .await - .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)? }; let mut active_algorithms = Vec::new(); @@ -1007,6 +1041,7 @@ pub async fn update_default_routing_config_for_profile( transaction_type: &enums::TransactionType, ) -> RouterResponse { metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(&metrics::CONTEXT, 1, &[]); + let db = state.store.as_ref(); let key_manager_state = &(&state).into(); diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index eb7a3af5751e..0c4015d3217b 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -1368,16 +1368,29 @@ impl GetProfileId for diesel_models::Refund { } } -#[cfg(feature = "payouts")] -impl GetProfileId for storage::Payouts { +#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))] +impl GetProfileId for api_models::routing::RoutingConfigRequest { + fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> { + self.profile_id.as_ref() + } +} + +#[cfg(all(feature = "v2", feature = "routing_v2"))] +impl GetProfileId for api_models::routing::RoutingConfigRequest { fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> { Some(&self.profile_id) } } -#[cfg(feature = "payouts")] -impl GetProfileId for (storage::Payouts, T, F) { + +impl GetProfileId for api_models::routing::RoutingRetrieveLinkQuery { fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> { - self.0.get_profile_id() + self.profile_id.as_ref() + } +} + +impl GetProfileId for diesel_models::routing_algorithm::RoutingProfileMetadata { + fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> { + Some(&self.profile_id) } } @@ -1387,6 +1400,19 @@ impl GetProfileId for domain::BusinessProfile { } } +#[cfg(feature = "payouts")] +impl GetProfileId for storage::Payouts { + fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> { + Some(&self.profile_id) + } +} +#[cfg(feature = "payouts")] +impl GetProfileId for (storage::Payouts, T, F) { + fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> { + self.0.get_profile_id() + } +} + /// Filter Objects based on profile ids pub(super) fn filter_objects_based_on_profile_id_list( profile_id_list_auth_layer: Option>, diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index c78caa9e7815..bd05740acae8 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -711,6 +711,17 @@ impl Routing { ) })), ) + .service(web::resource("/list/{profile_id}").route(web::get().to( + |state, req, path, query: web::Query| { + routing::list_routing_configs_for_profile( + state, + req, + query, + path, + &TransactionType::Payment, + ) + }, + ))) .service( web::resource("/default") .route(web::get().to(|state, req| { diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index aefc91f759c4..b68d09deeb22 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -34,6 +34,7 @@ pub async fn routing_create_config( state, auth.merchant_account, auth.key_store, + auth.profile_id, payload, transaction_type, ) @@ -74,6 +75,7 @@ pub async fn routing_link_config( state, auth.merchant_account, auth.key_store, + auth.profile_id, algorithm, transaction_type, ) @@ -110,7 +112,7 @@ pub async fn routing_link_config( flow, state, &req, - wrapper, + wrapper.clone(), |state, auth: auth::AuthenticationData, wrapper, _| { routing::link_routing_config_under_profile( state, @@ -124,11 +126,17 @@ pub async fn routing_link_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::ApiKeyAuth, - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuthProfileFromRoute { + profile_id: routing_payload_wrapper.profile_id, + required_permission: Permission::RoutingWrite, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuthProfileFromRoute { + profile_id: wrapper.profile_id, + required_permission: Permission::RoutingWrite, + }, api_locking::LockAction::NotApplicable, )) .await @@ -153,6 +161,7 @@ pub async fn routing_retrieve_config( state, auth.merchant_account, auth.key_store, + auth.profile_id, algorithm_id, ) }, @@ -187,6 +196,7 @@ pub async fn list_routing_configs( routing::retrieve_merchant_routing_dictionary( state, auth.merchant_account, + None, query_params, transaction_type, ) @@ -204,6 +214,50 @@ pub async fn list_routing_configs( .await } +#[cfg(feature = "olap")] +#[instrument(skip_all)] +pub async fn list_routing_configs_for_profile( + state: web::Data, + req: HttpRequest, + query: web::Query, + path: web::Path, + transaction_type: &enums::TransactionType, +) -> impl Responder { + let flow = Flow::RoutingRetrieveDictionary; + let path = path.into_inner(); + Box::pin(oss_api::server_wrap( + flow, + state, + &req, + query.into_inner(), + |state, auth: auth::AuthenticationData, query_params, _| { + routing::retrieve_merchant_routing_dictionary( + state, + auth.merchant_account, + auth.profile_id.map(|profile_id| vec![profile_id]), + query_params, + transaction_type, + ) + }, + #[cfg(not(feature = "release"))] + auth::auth_type( + &auth::HeaderAuth(auth::ApiKeyAuth), + &auth::JWTAuthProfileFromRoute { + profile_id: path, + required_permission: Permission::RoutingRead, + }, + req.headers(), + ), + #[cfg(feature = "release")] + &auth::JWTAuthProfileFromRoute { + profile_id: path, + required_permission: Permission::RoutingRead, + }, + api_locking::LockAction::NotApplicable, + )) + .await +} + #[cfg(all(feature = "olap", feature = "v2", feature = "routing_v2"))] #[instrument(skip_all)] pub async fn routing_unlink_config( @@ -213,11 +267,12 @@ pub async fn routing_unlink_config( transaction_type: &enums::TransactionType, ) -> impl Responder { let flow = Flow::RoutingUnlinkConfig; + let path = path.into_inner(); Box::pin(oss_api::server_wrap( flow, state, &req, - path.into_inner(), + path.clone(), |state, auth: auth::AuthenticationData, path, _| { routing::unlink_routing_config_under_profile( state, @@ -230,11 +285,17 @@ pub async fn routing_unlink_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::ApiKeyAuth, - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuthProfileFromRoute { + profile_id: path, + required_permission: Permission::RoutingWrite, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuthProfileFromRoute { + profile_id: path, + required_permission: Permission::RoutingWrite, + }, api_locking::LockAction::NotApplicable, )) .await @@ -264,6 +325,7 @@ pub async fn routing_unlink_config( auth.merchant_account, auth.key_store, payload_req, + auth.profile_id, transaction_type, ) }, @@ -374,11 +436,12 @@ pub async fn routing_retrieve_default_config( req: HttpRequest, path: web::Path, ) -> impl Responder { + let path = path.into_inner(); Box::pin(oss_api::server_wrap( Flow::RoutingRetrieveDefaultConfig, state, &req, - path.into_inner(), + path.clone(), |state, auth: auth::AuthenticationData, profile_id, _| { routing::retrieve_default_fallback_algorithm_for_profile( state, @@ -390,11 +453,17 @@ pub async fn routing_retrieve_default_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuthProfileFromRoute { + profile_id: path, + required_permission: Permission::RoutingRead, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuthProfileFromRoute { + profile_id: path, + required_permission: Permission::RoutingRead, + }, api_locking::LockAction::NotApplicable, )) .await @@ -636,31 +705,68 @@ pub async fn routing_retrieve_linked_config( ) -> impl Responder { use crate::services::authentication::AuthenticationData; let flow = Flow::RoutingRetrieveActiveConfig; - Box::pin(oss_api::server_wrap( - flow, - state, - &req, - query.into_inner(), - |state, auth: AuthenticationData, query_params, _| { - routing::retrieve_linked_routing_config( - state, - auth.merchant_account, - auth.key_store, - query_params, - transaction_type, - ) - }, - #[cfg(not(feature = "release"))] - auth::auth_type( - &auth::HeaderAuth(auth::ApiKeyAuth), + let query = query.into_inner(); + if let Some(profile_id) = query.profile_id.clone() { + Box::pin(oss_api::server_wrap( + flow, + state, + &req, + query.clone(), + |state, auth: AuthenticationData, query_params, _| { + routing::retrieve_linked_routing_config( + state, + auth.merchant_account, + auth.key_store, + auth.profile_id, + query_params, + transaction_type, + ) + }, + #[cfg(not(feature = "release"))] + auth::auth_type( + &auth::HeaderAuth(auth::ApiKeyAuth), + &auth::JWTAuthProfileFromRoute { + profile_id, + required_permission: Permission::RoutingRead, + }, + req.headers(), + ), + #[cfg(feature = "release")] + &auth::JWTAuthProfileFromRoute { + profile_id, + required_permission: Permission::RoutingRead, + }, + api_locking::LockAction::NotApplicable, + )) + .await + } else { + Box::pin(oss_api::server_wrap( + flow, + state, + &req, + query.clone(), + |state, auth: AuthenticationData, query_params, _| { + routing::retrieve_linked_routing_config( + state, + auth.merchant_account, + auth.key_store, + auth.profile_id, + query_params, + transaction_type, + ) + }, + #[cfg(not(feature = "release"))] + auth::auth_type( + &auth::HeaderAuth(auth::ApiKeyAuth), + &auth::JWTAuth(Permission::RoutingRead), + req.headers(), + ), + #[cfg(feature = "release")] &auth::JWTAuth(Permission::RoutingRead), - req.headers(), - ), - #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), - api_locking::LockAction::NotApplicable, - )) - .await + api_locking::LockAction::NotApplicable, + )) + .await + } } #[cfg(all( @@ -687,7 +793,7 @@ pub async fn routing_retrieve_linked_config( flow, state, &req, - wrapper, + wrapper.clone(), |state, auth: AuthenticationData, wrapper, _| { routing::retrieve_routing_config_under_profile( state, @@ -701,11 +807,17 @@ pub async fn routing_retrieve_linked_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuthProfileFromRoute { + profile_id: wrapper.profile_id, + required_permission: Permission::RoutingRead, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuthProfileFromRoute { + profile_id: wrapper.profile_id, + required_permission: Permission::RoutingRead, + }, api_locking::LockAction::NotApplicable, )) .await @@ -765,7 +877,7 @@ pub async fn routing_update_default_config_for_profile( Flow::RoutingUpdateDefaultConfig, state, &req, - routing_payload_wrapper, + routing_payload_wrapper.clone(), |state, auth: auth::AuthenticationData, wrapper, _| { routing::update_default_routing_config_for_profile( state, @@ -779,11 +891,17 @@ pub async fn routing_update_default_config_for_profile( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuthProfileFromRoute { + profile_id: routing_payload_wrapper.profile_id, + required_permission: Permission::RoutingWrite, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuthProfileFromRoute { + profile_id: routing_payload_wrapper.profile_id, + required_permission: Permission::RoutingWrite, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index a84f3a5a0e3d..4f9a222db5ed 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -1329,7 +1329,6 @@ where )) } } - pub struct JWTAuthMerchantAndProfileFromRoute { pub merchant_id: id_type::MerchantId, pub profile_id: id_type::ProfileId, @@ -1404,6 +1403,87 @@ where } } +pub struct JWTAuthProfileFromRoute { + pub profile_id: id_type::ProfileId, + pub required_permission: Permission, +} + +#[async_trait] +impl AuthenticateAndFetch for JWTAuthProfileFromRoute +where + A: SessionStateInfo + Sync, +{ + async fn authenticate_and_fetch( + &self, + request_headers: &HeaderMap, + state: &A, + ) -> RouterResult<(AuthenticationData, AuthenticationType)> { + let payload = parse_jwt_payload::(request_headers, state).await?; + if payload.check_in_blacklist(state).await? { + return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); + } + + let permissions = authorization::get_permissions(state, &payload).await?; + authorization::check_authorization(&self.required_permission, &permissions)?; + let key_manager_state = &(&state.session_state()).into(); + let key_store = state + .store() + .get_merchant_key_store_by_merchant_id( + key_manager_state, + &payload.merchant_id, + &state.store().get_master_key().to_vec().into(), + ) + .await + .to_not_found_response(errors::ApiErrorResponse::InvalidJwtToken) + .attach_printable("Failed to fetch merchant key store for the merchant id")?; + + let merchant = state + .store() + .find_merchant_account_by_merchant_id( + key_manager_state, + &payload.merchant_id, + &key_store, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::InvalidJwtToken) + .attach_printable("Failed to fetch merchant account for the merchant id")?; + + if let Some(ref payload_profile_id) = payload.profile_id { + if *payload_profile_id != self.profile_id { + return Err(report!(errors::ApiErrorResponse::InvalidJwtToken)); + } else { + // if both of them are same then proceed with the profile id present in the request + let auth = AuthenticationData { + merchant_account: merchant, + key_store, + profile_id: Some(self.profile_id.clone()), + }; + Ok(( + auth.clone(), + AuthenticationType::MerchantJwt { + merchant_id: auth.merchant_account.get_id().clone(), + user_id: Some(payload.user_id), + }, + )) + } + } else { + // if profile_id is not present in the auth_layer itself then no change in behaviour + let auth = AuthenticationData { + merchant_account: merchant, + key_store, + profile_id: payload.profile_id, + }; + Ok(( + auth.clone(), + AuthenticationType::MerchantJwt { + merchant_id: auth.merchant_account.get_id().clone(), + user_id: Some(payload.user_id), + }, + )) + } + } +} + pub async fn parse_jwt_payload(headers: &HeaderMap, state: &A) -> RouterResult where T: serde::de::DeserializeOwned,