Bug: REFACTOR: check the authenticity of profile_id being used for all the routing routes



After this refactor goes in, we will have an auth layer verifying the autheticity of profile being sent in the request at max there can be 4 cases:
1. profile_id not present in the request: provide the requested details for the profile present in auth headers
2. profile_id not present in the auth_layer: provide the details requested no change in behaviour
3. same profile_id present in both the places(request as well as the auth_layer): provide the details for the profiles
4. mismatch between the profiles in both the layers: Throw unauthorized error.
diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs
index 1416e985523..7b7a59bc866 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<RoutableConnectorChoice>,
 }
 
-#[derive(Debug, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
 pub struct RoutingRetrieveQuery {
     pub limit: Option<u16>,
     pub offset: Option<u8>,
 }
 
-#[derive(Debug, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
 pub struct RoutingRetrieveLinkQuery {
     pub profile_id: Option<common_utils::id_type::ProfileId>,
 }
 
-#[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 512f97b8c9e..9efe2cd6ab2 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<Vec<common_utils::id_type::ProfileId>>,
     query_params: RoutingRetrieveQuery,
     transaction_type: &enums::TransactionType,
 ) -> RouterResponse<routing_types::RoutingKind> {
     metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE.add(&metrics::CONTEXT, 1, &[]);
 
-    let routing_metadata = state
+    let routing_metadata: Vec<diesel_models::routing_algorithm::RoutingProfileMetadata> = 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<common_utils::id_type::ProfileId>,
     request: routing_types::RoutingConfigRequest,
     transaction_type: &enums::TransactionType,
 ) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
@@ -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<common_utils::id_type::ProfileId>,
     request: routing_types::RoutingConfigRequest,
     transaction_type: &enums::TransactionType,
 ) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
@@ -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<common_utils::id_type::ProfileId>,
     algorithm_id: common_utils::id_type::RoutingId,
     transaction_type: &enums::TransactionType,
 ) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
@@ -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<common_utils::id_type::ProfileId>,
     algorithm_id: common_utils::id_type::RoutingId,
 ) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
     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<common_utils::id_type::ProfileId>,
     algorithm_id: common_utils::id_type::RoutingId,
 ) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
     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<common_utils::id_type::ProfileId>,
     transaction_type: &enums::TransactionType,
 ) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
     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<common_utils::id_type::ProfileId>,
     query_params: routing_types::RoutingRetrieveLinkQuery,
     transaction_type: &enums::TransactionType,
 ) -> RouterResponse<routing_types::LinkedRoutingConfigRetrieveResponse> {
@@ -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<routing_types::ProfileDefaultRoutingConfig> {
     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 2fcf8a24773..41e87a19337 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<T, F> 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<T, F> 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<T: GetProfileId>(
     profile_id_list_auth_layer: Option<Vec<common_utils::id_type::ProfileId>>,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index c78caa9e781..bd05740acae 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<RoutingRetrieveQuery>| {
+                    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 aefc91f759c..b68d09deeb2 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<AppState>,
+    req: HttpRequest,
+    query: web::Query<RoutingRetrieveQuery>,
+    path: web::Path<common_utils::id_type::ProfileId>,
+    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<common_utils::id_type::ProfileId>,
 ) -> 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 a84f3a5a0e3..4f9a222db5e 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<A> AuthenticateAndFetch<AuthenticationData, A> 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::<A, AuthToken>(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<A, T>(headers: &HeaderMap, state: &A) -> RouterResult<T>
 where
     T: serde::de::DeserializeOwned,

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [x] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
This change will ensure that the profile id being sent in params, belongs to the merchant using them.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Cannot be tested right now because currently we are not including profile_id in JWT.
Was able to compile the code.

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
