fix(authentication): fixed terminal state persistence for redirect response (#8916)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Sahkal Poddar
2025-08-18 13:17:21 +05:30
committed by GitHub
parent 8be69c267e
commit 375e9be9fd
2 changed files with 33 additions and 4 deletions

View File

@ -7655,6 +7655,10 @@ impl TransactionStatus {
Self::ChallengeRequired | Self::ChallengeRequiredDecoupledAuthentication Self::ChallengeRequired | Self::ChallengeRequiredDecoupledAuthentication
) )
} }
pub fn is_terminal_state(self) -> bool {
matches!(self, Self::Success | Self::Failure)
}
} }
#[derive( #[derive(

View File

@ -903,6 +903,9 @@ pub async fn authentication_eligibility_core(
) )
}) })
.transpose()?; .transpose()?;
ensure_not_terminal_status(authentication.trans_status.clone())?;
let key_manager_state = (&state).into(); let key_manager_state = (&state).into();
let profile_id = core_utils::get_profile_id_from_business_details( let profile_id = core_utils::get_profile_id_from_business_details(
@ -1172,6 +1175,8 @@ pub async fn authentication_authenticate_core(
}) })
.transpose()?; .transpose()?;
ensure_not_terminal_status(authentication.trans_status.clone())?;
let key_manager_state = (&state).into(); let key_manager_state = (&state).into();
let profile_id = authentication.profile_id.clone(); let profile_id = authentication.profile_id.clone();
@ -1656,6 +1661,9 @@ pub async fn authentication_post_sync_core(
.to_not_found_response(ApiErrorResponse::AuthenticationNotFound { .to_not_found_response(ApiErrorResponse::AuthenticationNotFound {
id: authentication_id.get_string_repr().to_owned(), id: authentication_id.get_string_repr().to_owned(),
})?; })?;
ensure_not_terminal_status(authentication.trans_status.clone())?;
let key_manager_state = (&state).into(); let key_manager_state = (&state).into();
let business_profile = db let business_profile = db
.find_business_profile_by_profile_id( .find_business_profile_by_profile_id(
@ -1691,7 +1699,7 @@ pub async fn authentication_post_sync_core(
) )
.await?; .await?;
utils::external_authentication_update_trackers( let updated_authentication = utils::external_authentication_update_trackers(
&state, &state,
post_auth_response, post_auth_response,
authentication.clone(), authentication.clone(),
@ -1711,7 +1719,7 @@ pub async fn authentication_post_sync_core(
.attach_printable("authentication_connector_details not configured by the merchant")?; .attach_printable("authentication_connector_details not configured by the merchant")?;
let authentication_response = AuthenticationAuthenticateResponse::foreign_try_from(( let authentication_response = AuthenticationAuthenticateResponse::foreign_try_from((
&authentication, &updated_authentication,
None, None,
None, None,
authentication_details, authentication_details,
@ -1723,13 +1731,30 @@ pub async fn authentication_post_sync_core(
&authentication_response, &authentication_response,
authentication_connector.to_string(), authentication_connector.to_string(),
authentication.return_url, authentication.return_url,
authentication updated_authentication
.authentication_client_secret .authentication_client_secret
.clone() .clone()
.map(masking::Secret::new) .map(masking::Secret::new)
.as_ref(), .as_ref(),
authentication.amount, updated_authentication.amount,
)?; )?;
Ok(hyperswitch_domain_models::api::ApplicationResponse::JsonForRedirection(redirect_response)) Ok(hyperswitch_domain_models::api::ApplicationResponse::JsonForRedirection(redirect_response))
} }
fn ensure_not_terminal_status(
status: Option<common_enums::TransactionStatus>,
) -> Result<(), error_stack::Report<ApiErrorResponse>> {
status
.filter(|s| s.clone().is_terminal_state())
.map(|s| {
Err(error_stack::Report::new(
ApiErrorResponse::UnprocessableEntity {
message: format!(
"authentication status for the given authentication_id is already in {s}"
),
},
))
})
.unwrap_or(Ok(()))
}