hyperswitch icon indicating copy to clipboard operation
hyperswitch copied to clipboard

fix(diesel_models): enhance 3DS authentication detection for v1/v2 support

Open kdt523 opened this issue 2 months ago • 2 comments

Type of Change

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

Description

This PR fixes issue #9906 where ACI connector with Juspay MPI was not triggering the 3DS redirect URL for customer authentication.

Problem: The existing is_separate_authn_required() method in crates/diesel_models/src/authentication.rs only checked for 3DS version 2.x (maximum_supported_version.major == 2). When Juspay MPI returns 3DS version 1.x or a null/missing version field, the method incorrectly returned false, causing the payment flow to skip the required customer authentication step and proceed directly to "requires_capture" status instead of "requires_customer_action" with a redirect URL.

Solution: Enhanced the authentication detection logic with a multi-layer validation approach:

  1. Enhanced is_separate_authn_required() method (crates/diesel_models/src/authentication.rs):

    • Added checks for authentication flow indicators (ACS URL, 3DS method URL, challenge request)
    • Now returns true if: authentication connector exists AND authentication is not completed AND (has 3DS v2 OR has authentication flow URLs)
    • Supports both 3DS v1 and v2 flows
  2. Defensive flag setting (crates/router/src/core/payments/operations/payment_confirm.rs):

    • Added triple-layer validation for external_three_ds_authentication_attempted flag
    • Primary check: Uses improved is_separate_authn_required() logic
    • Fallback 1: Checks if authentication connector exists
    • Fallback 2: Checks if authentication status is Pending or Started
    • Ensures authentication requirements are properly detected even when version information is incomplete

Edge Cases Handled:

  • Missing maximum_supported_version field
  • 3DS version 1.x flows
  • Partial authentication responses from MPIs
  • Null or incomplete version information

Additional Changes

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

Motivation and Context

Fixes #9906

Context: When using ACI connector with Juspay as the external 3DS MPI (Merchant Plug-In), the payment flow was not properly detecting that customer authentication was required. This resulted in:

  • Missing redirect_to_url in the next_action field
  • Payment proceeding to "requires_capture" status instead of "requires_customer_action"
  • Customer unable to complete 3DS authentication challenge

The root cause was the authentication detection logic only supporting 3DS version 2.x, while Juspay MPI can return version 1.x or omit version information entirely. This prevented the redirect URL from being returned to the customer for authentication.

How did you test it?

Local Testing:

  • Code formatting verified with cargo +nightly fmt
  • Syntax validation via VS Code Rust Analyzer (no errors)
  • Manual code review for logic correctness and edge cases
  • cargo clippy and cargo test blocked locally due to Windows long path limitation with git dependencies
  • Git checkout error: cannot checkout to invalid path 'postman/collection-dir/...' (exceeds Windows MAX_PATH 260 chars)
  • Enabled git config --global core.longpaths true but issue persists with cached dependencies

CI Testing: CI will verify in Linux environment:

  • Code linting with cargo clippy --all-features
  • Unit tests with cargo test --all-features
  • Integration tests

Manual Verification:

  • Both modified files compile without errors in VS Code Rust Analyzer
  • Logic manually traced for the following scenarios:
    • 3DS v2 with version field → correctly detected
    • 3DS v1 with version field → correctly detected (new)
    • Missing version field with ACS URL → correctly detected (new)
    • Missing version field with 3DS method URL → correctly detected (new)
    • Missing version field with challenge request → correctly detected (new)
    • Completed authentication (Success status) → correctly skipped
    • No authentication connector → correctly skipped

Checklist

  • [x] I formatted the code cargo +nightly fmt --all
  • [ ] I addressed lints thrown by cargo clippy (will be verified by CI due to local Windows path limitation)
  • [x] I reviewed the submitted code
  • [x] I added unit tests for my changes where possible (no new unit tests added; existing tests cover authentication logic, changes are defensive enhancements)

kdt523 avatar Oct 23 '25 08:10 kdt523

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/payments/operations/payment_confirm.rs  40% smaller
  crates/diesel_models/src/authentication.rs  24% smaller

semanticdiff-com[bot] avatar Oct 23 '25 08:10 semanticdiff-com[bot]

Hi @juspay/hyperswitch-core @juspay/hyperswitch-framework I've updated the branch to sync with main.
Could you please review this PR and approve the workflows when you get a chance?
The workflows are currently awaiting maintainer approval, and merging is blocked until the required code owner reviews are completed.
Thanks a lot for your time and help!

kdt523 avatar Oct 24 '25 18:10 kdt523