flutter_stripe icon indicating copy to clipboard operation
flutter_stripe copied to clipboard

Closing 3DS secure window on Android causes 'Cancelled' event even when authentication is marked complete

Open codecoded opened this issue 2 years ago • 6 comments

Describe the bug I've recently had to ensure we handle 3DS for all payments. Calling nextAction brings up an in-app browser flow to handle the 3DS. Once the process is finished, when no returnUrl is set in the backend stripe call, the browser shows a Authentication Complete message and you can now close this window. On iOS this responds fine and I can then continue the payment (confirm), but on Android, it triggers a cancel event and throws an exception - I never received a response back from the nextAction request so I cannot continue the request.

This is tested on real Android device, but only running from within local development , not via Google Play

To Reproduce Steps to reproduce the behavior:

  1. Using Android and 3DS enabled on Stripe, enter a card number that requires 3DS authentcation: 4000000000003063 (test card) note, using the default test card of 4242424242424242 will give an immediate Authentication Compelte screen

  2. Create a payment intent on the server using the payment method id from the added card and manual confirmation

Client call to bespoke server payment API

_result = await PurchaseService.makePayment(_processingOptions.purchaseRequest);

Server request to Stripe within the bespoke payment API

await Stripe.paymentIntents.create({
                amount: amountPayable,
                currency: "usd",
                customer: stripeCustomerId,
                payment_method: paymentMethodId,
                payment_method_types: ["card"],
                confirm: true,
                confirmation_method: isLegacy ? 'automatic' : 'manual',
                use_stripe_sdk: true,
                error_on_requires_action: isLegacy,
                // return_url: <using universal links here doesn't work on iOS because of use of in-app browser :-( >
            }, {
                idempotencyKey: requestId,
            });
  1. On client, handle the response to trigger next action and listen for response
    if (_result!.isDone && _result!.data != null) {
      final data = _result!.data!;
      if (data.requiresAction) {
        try {
          final stripeResponse = await Stripe.instance.handleNextAction(data.clientSecret!);
          _processingOptions.purchaseRequest.setToConfirmation(stripeResponse.id);
          _result = await PurchaseService.makePayment(_processingOptions.purchaseRequest);
        } on StripeException catch (error) {
          _result = DataRequest.error(error.error.localizedMessage);
        } catch (error) {
          _result = DataRequest.error(null);
        }
      }
    }
 
  1. On Android, when the message from Stripe is Authentication Complete, close this window - press Close. A StripeException will be thrown instead of a success response.

Expected behavior When clicking close on a succesful authentication, I expect handleNextAction to return a success response so the payment can be confirmed on the server. This works for iOS but not Android

Smartphone

  • Device: Samsung S9
  • OS: Android 10
  • Package version: 3.0.0 / 3.3.0
  • Flutter version 3.0.0

Additional context Setting the returnUrl fixes the problem on Android however, cannot use universal links as opens the website on iOS due to not using native browser for the 3DS, and running into a current issue using application scheme not working on iOS (not sure why on that yet - have yet to find time to resolve, return link generated by Stripe works fine when accessed by say iOS notes or any external process!)

codecoded avatar Jul 15 '22 03:07 codecoded

+1

kekko7072 avatar Jul 20 '22 10:07 kekko7072

I am also getting same issue

hiteshtank avatar Jul 21 '22 11:07 hiteshtank

Same issue here with v4.0.0 as well. This is a very serious issue as it breaks the payment on the Android platform.

musthafa1996 avatar Jul 21 '22 17:07 musthafa1996

Temporary I solved it like put condition before doing paymentIntent.create to check if app is running on Android device or IOS device. if its running in Android then I am passing return url while paymentIntent.create and if its IOS then no need to pass return url. this way it works in both and returns success for Android and IOS both

hiteshtank avatar Jul 22 '22 10:07 hiteshtank

Temporary I solved it like put condition before doing paymentIntent.create to check if app is running on Android device or IOS device. if its running in Android then I am passing return url while paymentIntent.create and if its IOS then no need to pass return url. this way it works in both and returns success for Android and IOS both

This was a great solution. The 3DS auth screen closes automatically after the authentication completes. Thank you @hiteshtank :)

musthafa1996 avatar Jul 23 '22 09:07 musthafa1996

How did you get this working? @hiteshtank @musthafa1996

alexdriba avatar Oct 10 '22 14:10 alexdriba

@jonasbark @hiteshtank For 3DS cards verification Stripe Displays a popup on the web and webview on the mobile. I have not provided the return_url but it's returning me back to My App/website. Question is: Do I need to provide return_url OR is there any chance it will take me outside the app and move to another app/website and will return to my app using return_url?

adnan-nazir avatar Oct 20 '22 17:10 adnan-nazir

should be fixed in the latest releases of our sdk library. If this is not the case feel free to reopen it

remonh87 avatar Oct 31 '23 15:10 remonh87