feat(core): Add V2 Authentication to all available endpoints (#7487)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Bernard Eugine <114725419+bernard-eugine@users.noreply.github.com>
This commit is contained in:
Gaurav Rawat
2025-03-13 01:49:09 +05:30
committed by GitHub
parent 4f6174d1bf
commit 3667a7ffd2
9 changed files with 327 additions and 52 deletions

View File

@ -483,6 +483,6 @@ pub enum RevenueRecoveryError {
PaymentIntentCreateFailed,
#[error("Source verification failed for billing connector")]
WebhookAuthenticationFailed,
#[error("Payment merchant connector account not found using acccount reference id")]
#[error("Payment merchant connector account not found using account reference id")]
PaymentMerchantConnectorAccountNotFound,
}

View File

@ -8,7 +8,7 @@ use crate::{
types::api::admin,
};
#[cfg(feature = "olap")]
#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all, fields(flow = ?Flow::OrganizationCreate))]
pub async fn organization_create(
state: web::Data<AppState>,
@ -27,8 +27,26 @@ pub async fn organization_create(
))
.await
}
#[cfg(feature = "olap")]
#[cfg(all(feature = "olap", feature = "v2"))]
#[instrument(skip_all, fields(flow = ?Flow::OrganizationCreate))]
pub async fn organization_create(
state: web::Data<AppState>,
req: HttpRequest,
json_payload: web::Json<admin::OrganizationCreateRequest>,
) -> HttpResponse {
let flow = Flow::OrganizationCreate;
Box::pin(api::server_wrap(
flow,
state,
&req,
json_payload.into_inner(),
|state, _, req, _| create_organization(state, req),
&auth::V2AdminApiAuth,
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all, fields(flow = ?Flow::OrganizationUpdate))]
pub async fn organization_update(
state: web::Data<AppState>,
@ -59,8 +77,38 @@ pub async fn organization_update(
))
.await
}
#[cfg(feature = "olap")]
#[cfg(all(feature = "olap", feature = "v2"))]
#[instrument(skip_all, fields(flow = ?Flow::OrganizationUpdate))]
pub async fn organization_update(
state: web::Data<AppState>,
req: HttpRequest,
org_id: web::Path<common_utils::id_type::OrganizationId>,
json_payload: web::Json<admin::OrganizationUpdateRequest>,
) -> HttpResponse {
let flow = Flow::OrganizationUpdate;
let organization_id = org_id.into_inner();
let org_id = admin::OrganizationId {
organization_id: organization_id.clone(),
};
Box::pin(api::server_wrap(
flow,
state,
&req,
json_payload.into_inner(),
|state, _, req, _| update_organization(state, org_id.clone(), req),
auth::auth_type(
&auth::V2AdminApiAuth,
&auth::JWTAuthOrganizationFromRoute {
organization_id,
required_permission: Permission::OrganizationAccountWrite,
},
req.headers(),
),
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all, fields(flow = ?Flow::OrganizationRetrieve))]
pub async fn organization_retrieve(
state: web::Data<AppState>,
@ -92,6 +140,38 @@ pub async fn organization_retrieve(
.await
}
#[cfg(all(feature = "olap", feature = "v2"))]
#[instrument(skip_all, fields(flow = ?Flow::OrganizationRetrieve))]
pub async fn organization_retrieve(
state: web::Data<AppState>,
req: HttpRequest,
org_id: web::Path<common_utils::id_type::OrganizationId>,
) -> HttpResponse {
let flow = Flow::OrganizationRetrieve;
let organization_id = org_id.into_inner();
let payload = admin::OrganizationId {
organization_id: organization_id.clone(),
};
Box::pin(api::server_wrap(
flow,
state,
&req,
payload,
|state, _, req, _| get_organization(state, req),
auth::auth_type(
&auth::V2AdminApiAuth,
&auth::JWTAuthOrganizationFromRoute {
organization_id,
required_permission: Permission::OrganizationAccountRead,
},
req.headers(),
),
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountCreate))]
pub async fn merchant_account_create(
@ -144,15 +224,13 @@ pub async fn merchant_account_create(
&req,
new_request_payload_with_org_id,
|state, _, req, _| create_merchant_account(state, req),
&auth::AdminApiAuth,
&auth::V2AdminApiAuth,
api_locking::LockAction::NotApplicable,
))
.await
}
/// Merchant Account - Retrieve
///
/// Retrieve a merchant account details.
#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountRetrieve))]
pub async fn retrieve_merchant_account(
state: web::Data<AppState>,
@ -187,6 +265,44 @@ pub async fn retrieve_merchant_account(
.await
}
/// Merchant Account - Retrieve
///
/// Retrieve a merchant account details.
#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountRetrieve))]
pub async fn retrieve_merchant_account(
state: web::Data<AppState>,
req: HttpRequest,
mid: web::Path<common_utils::id_type::MerchantId>,
) -> HttpResponse {
let flow = Flow::MerchantsAccountRetrieve;
let merchant_id = mid.into_inner();
let payload = admin::MerchantId {
merchant_id: merchant_id.clone(),
};
api::server_wrap(
flow,
state,
&req,
payload,
|state, _, req, _| get_merchant_account(state, req, None),
auth::auth_type(
&auth::V2AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id,
// This should ideally be MerchantAccountRead, but since FE is calling this API for
// profile level users currently keeping this as ProfileAccountRead. FE is removing
// this API call for profile level users.
// TODO: Convert this to MerchantAccountRead once FE changes are done.
required_permission: Permission::ProfileAccountRead,
},
req.headers(),
),
api_locking::LockAction::NotApplicable,
)
.await
}
#[cfg(all(feature = "olap", feature = "v2"))]
#[instrument(skip_all, fields(flow = ?Flow::MerchantAccountList))]
pub async fn merchant_account_list(
@ -207,7 +323,7 @@ pub async fn merchant_account_list(
organization_id,
|state, _, request, _| list_merchant_account(state, request),
auth::auth_type(
&auth::AdminApiAuth,
&auth::V2AdminApiAuth,
&auth::JWTAuthMerchantFromHeader {
required_permission: Permission::MerchantAccountRead,
},
@ -248,6 +364,35 @@ pub async fn merchant_account_list(
/// Merchant Account - Update
///
/// To update an existing merchant account. Helpful in updating merchant details such as email, contact details, or other configuration details like webhook, routing algorithm etc
#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountUpdate))]
pub async fn update_merchant_account(
state: web::Data<AppState>,
req: HttpRequest,
mid: web::Path<common_utils::id_type::MerchantId>,
json_payload: web::Json<admin::MerchantAccountUpdate>,
) -> HttpResponse {
let flow = Flow::MerchantsAccountUpdate;
let merchant_id = mid.into_inner();
Box::pin(api::server_wrap(
flow,
state,
&req,
json_payload.into_inner(),
|state, _, req, _| merchant_account_update(state, &merchant_id, None, req),
auth::auth_type(
&auth::V2AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantAccountWrite,
},
req.headers(),
),
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountUpdate))]
pub async fn update_merchant_account(
state: web::Data<AppState>,
@ -279,6 +424,30 @@ pub async fn update_merchant_account(
/// Merchant Account - Delete
///
/// To delete a merchant account
#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountDelete))]
pub async fn delete_merchant_account(
state: web::Data<AppState>,
req: HttpRequest,
mid: web::Path<common_utils::id_type::MerchantId>,
) -> HttpResponse {
let flow = Flow::MerchantsAccountDelete;
let mid = mid.into_inner();
let payload = web::Json(admin::MerchantId { merchant_id: mid }).into_inner();
api::server_wrap(
flow,
state,
&req,
payload,
|state, _, req, _| merchant_account_delete(state, req.merchant_id),
&auth::V2AdminApiAuth,
api_locking::LockAction::NotApplicable,
)
.await
}
#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountDelete))]
pub async fn delete_merchant_account(
state: web::Data<AppState>,
@ -712,7 +881,7 @@ pub async fn connector_update(
payload,
|state, _, req, _| update_connector(state, &merchant_id, None, &id, req),
auth::auth_type(
&auth::AdminApiAuth,
&auth::V2AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantConnectorWrite,

View File

@ -268,7 +268,7 @@ pub async fn api_key_revoke(
(&merchant_id, &key_id),
|state, _, (merchant_id, key_id), _| api_keys::revoke_api_key(state, merchant_id, key_id),
auth::auth_type(
&auth::AdminApiAuth,
&auth::V2AdminApiAuth,
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantApiKeyWrite,

View File

@ -8,7 +8,34 @@ use crate::{
services::{api, authentication as auth, authorization::permissions::Permission},
types::api::customers,
};
#[cfg(all(feature = "v2", feature = "customer_v2"))]
#[instrument(skip_all, fields(flow = ?Flow::CustomersCreate))]
pub async fn customers_create(
state: web::Data<AppState>,
req: HttpRequest,
json_payload: web::Json<customers::CustomerRequest>,
) -> HttpResponse {
let flow = Flow::CustomersCreate;
Box::pin(api::server_wrap(
flow,
state,
&req,
json_payload.into_inner(),
|state, auth: auth::AuthenticationData, req, _| {
create_customer(state, auth.merchant_account, auth.key_store, req)
},
auth::auth_type(
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantCustomerWrite,
},
req.headers(),
),
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
#[instrument(skip_all, fields(flow = ?Flow::CustomersCreate))]
pub async fn customers_create(
state: web::Data<AppState>,
@ -115,7 +142,42 @@ pub async fn customers_retrieve(
))
.await
}
#[cfg(all(feature = "v2", feature = "customer_v2"))]
#[instrument(skip_all, fields(flow = ?Flow::CustomersList))]
pub async fn customers_list(
state: web::Data<AppState>,
req: HttpRequest,
query: web::Query<customers::CustomerListRequest>,
) -> HttpResponse {
let flow = Flow::CustomersList;
let payload = query.into_inner();
api::server_wrap(
flow,
state,
&req,
payload,
|state, auth: auth::AuthenticationData, request, _| {
list_customers(
state,
auth.merchant_account.get_id().to_owned(),
None,
auth.key_store,
request,
)
},
auth::auth_type(
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantCustomerRead,
},
req.headers(),
),
api_locking::LockAction::NotApplicable,
)
.await
}
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
#[instrument(skip_all, fields(flow = ?Flow::CustomersList))]
pub async fn customers_list(
state: web::Data<AppState>,
@ -219,7 +281,7 @@ pub async fn customers_update(
)
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantCustomerWrite,
},
@ -249,7 +311,7 @@ pub async fn customers_delete(
delete_customer(state, auth.merchant_account, id, auth.key_store)
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantCustomerWrite,
},

View File

@ -78,7 +78,7 @@ pub async fn client_secret_create(
req.headers(),
)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -99,7 +99,7 @@ pub async fn client_secret_delete(
&req,
payload,
|state, _: auth::AuthenticationData, req, _| helpers::delete_client_secret(state, req),
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await

View File

@ -95,7 +95,7 @@ pub async fn create_payment_method_api(
))
.await
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -214,7 +214,7 @@ pub async fn payment_method_retrieve_api(
auth.merchant_account,
)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -246,7 +246,7 @@ pub async fn payment_method_delete_api(
auth.merchant_account,
)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -613,7 +613,7 @@ pub async fn list_customer_payment_method_api(
)
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantCustomerRead,
},

View File

@ -147,9 +147,9 @@ pub async fn payments_create_intent(
)
},
match env::which() {
env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth),
env::Env::Production => &auth::V2ApiKeyAuth,
_ => auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfilePaymentWrite,
},
@ -210,7 +210,7 @@ pub async fn payments_get_intent(
auth.platform_merchant_account,
)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -249,9 +249,9 @@ pub async fn payments_create_and_confirm_intent(
)
},
match env::which() {
env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth),
env::Env::Production => &auth::V2ApiKeyAuth,
_ => auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfilePaymentWrite,
},
@ -313,7 +313,7 @@ pub async fn payments_update_intent(
auth.platform_merchant_account,
)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -825,7 +825,7 @@ pub async fn payments_connector_session(
tracing::Span::current().record("payment_id", global_payment_id.get_string_repr());
let internal_payload = internal_payload_types::PaymentsGenericRequestWithResourceId {
global_payment_id,
global_payment_id: global_payment_id.clone(),
payload: json_payload.into_inner(),
};
@ -868,7 +868,9 @@ pub async fn payments_connector_session(
auth.platform_merchant_account,
)
},
&auth::HeaderAuth(auth::PublishableKeyAuth),
&auth::V2ClientAuth(common_utils::types::authentication::ResourceId::Payment(
global_payment_id,
)),
locking_action,
))
.await
@ -1247,7 +1249,7 @@ pub async fn payments_list(
payments::list_payments(state, auth.merchant_account, auth.key_store, req)
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantPaymentRead,
},
@ -2423,7 +2425,7 @@ pub async fn payment_confirm_intent(
tracing::Span::current().record("payment_id", global_payment_id.get_string_repr());
let internal_payload = internal_payload_types::PaymentsGenericRequestWithResourceId {
global_payment_id,
global_payment_id: global_payment_id.clone(),
payload: json_payload.into_inner(),
};
@ -2468,7 +2470,9 @@ pub async fn payment_confirm_intent(
))
.await
},
&auth::PublishableKeyAuth,
&auth::V2ClientAuth(common_utils::types::authentication::ResourceId::Payment(
global_payment_id,
)),
locking_action,
))
.await
@ -2540,7 +2544,7 @@ pub async fn proxy_confirm_intent(
header_payload.clone(),
))
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
locking_action,
))
.await
@ -2611,7 +2615,7 @@ pub async fn payment_status(
.await
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfilePaymentRead,
},
@ -2657,7 +2661,7 @@ pub async fn payment_get_intent_using_merchant_reference_id(
))
.await
},
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))
.await
@ -2776,7 +2780,7 @@ pub async fn payments_capture(
.await
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfileAccountWrite,
},
@ -2802,7 +2806,7 @@ pub async fn list_payment_methods(
tracing::Span::current().record("payment_id", global_payment_id.get_string_repr());
let internal_payload = internal_payload_types::PaymentsGenericRequestWithResourceId {
global_payment_id,
global_payment_id: global_payment_id.clone(),
payload,
};
@ -2829,7 +2833,9 @@ pub async fn list_payment_methods(
&header_payload,
)
},
&auth::PublishableKeyAuth,
&auth::V2ClientAuth(common_utils::types::authentication::ResourceId::Payment(
global_payment_id,
)),
api_locking::LockAction::NotApplicable,
))
.await

View File

@ -82,7 +82,7 @@ pub async fn routing_create_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfileRoutingWrite,
},
@ -170,7 +170,7 @@ pub async fn routing_link_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::ApiKeyAuth,
&auth::V2ApiKeyAuth,
&auth::JWTAuthProfileFromRoute {
profile_id: wrapper.profile_id,
required_permission: Permission::MerchantRoutingWrite,
@ -252,7 +252,7 @@ pub async fn routing_retrieve_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfileRoutingRead,
},
@ -373,7 +373,7 @@ pub async fn routing_unlink_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::ApiKeyAuth,
&auth::V2ApiKeyAuth,
&auth::JWTAuthProfileFromRoute {
profile_id: path,
required_permission: Permission::MerchantRoutingWrite,
@ -459,7 +459,7 @@ pub async fn routing_update_default_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::MerchantRoutingWrite,
},
@ -535,7 +535,7 @@ pub async fn routing_retrieve_default_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuthProfileFromRoute {
profile_id: path,
required_permission: Permission::MerchantRoutingRead,
@ -749,7 +749,7 @@ pub async fn upsert_decision_manager_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfileThreeDsDecisionManagerWrite,
},
@ -818,7 +818,7 @@ pub async fn retrieve_decision_manager_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuth {
permission: Permission::ProfileThreeDsDecisionManagerWrite,
},
@ -976,7 +976,7 @@ pub async fn routing_retrieve_linked_config(
},
#[cfg(not(feature = "release"))]
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::V2ApiKeyAuth,
&auth::JWTAuthProfileFromRoute {
profile_id: wrapper.profile_id,
required_permission: Permission::ProfileRoutingRead,

View File

@ -1064,6 +1064,44 @@ where
}
}
#[derive(Debug, Default)]
pub struct V2AdminApiAuth;
#[async_trait]
impl<A> AuthenticateAndFetch<(), A> for V2AdminApiAuth
where
A: SessionStateInfo + Sync,
{
async fn authenticate_and_fetch(
&self,
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let header_map_struct = HeaderMapStruct::new(request_headers);
let auth_string = header_map_struct.get_auth_string_from_header()?;
let request_admin_api_key = auth_string
.split(',')
.find_map(|part| part.trim().strip_prefix("admin-api-key="))
.ok_or_else(|| {
report!(errors::ApiErrorResponse::Unauthorized)
.attach_printable("Unable to parse admin_api_key")
})?;
if request_admin_api_key.is_empty() {
return Err(errors::ApiErrorResponse::Unauthorized)
.attach_printable("Admin Api key is empty");
}
let conf = state.conf();
let admin_api_key = &conf.secrets.get_inner().admin_api_key;
if request_admin_api_key != admin_api_key.peek() {
Err(report!(errors::ApiErrorResponse::Unauthorized)
.attach_printable("Admin Authentication Failure"))?;
}
Ok(((), AuthenticationType::AdminApiKey))
}
}
#[derive(Debug)]
pub struct AdminApiAuthWithMerchantIdFromRoute(pub id_type::MerchantId);
@ -1130,7 +1168,7 @@ where
throw_error_if_platform_merchant_authentication_required(request_headers)?;
}
AdminApiAuth
V2AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
@ -1194,7 +1232,7 @@ where
throw_error_if_platform_merchant_authentication_required(request_headers)?;
}
AdminApiAuth
V2AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
@ -1400,7 +1438,7 @@ where
throw_error_if_platform_merchant_authentication_required(request_headers)?;
}
AdminApiAuth
V2AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
@ -1465,7 +1503,7 @@ where
throw_error_if_platform_merchant_authentication_required(request_headers)?;
}
AdminApiAuth
V2AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;