Ionic 5 IOS & Stripe Payment Request Button - Stripe.js integrations must use HTTPS

Viewed 1218

I'm trying to add a Payment Request Button to my Ionic 5 app. However, no matter how I run the app, I always get the following message and the button won't show.

[warn] - You may test your Stripe.js integration over HTTP. However, live Stripe.js integrations must use HTTPS.

I'm loading the Stripe API over https

  <script src="https://js.stripe.com/v3/"></script>

I've imported it in to my page

declare var Stripe;

// Check the availability of the Payment Request API first.
const prButton = elements.create('paymentRequestButton', {
    paymentRequest,
});

paymentRequest.canMakePayment().then(result => {
   if (result) {
       prButton.mount('#payment-request-button');
   } else {
       document.getElementById('payment-request-button').style.display = 'none';
   }

);

I've tried running it in Safari on Mac (running with --ssl and a valid certificate), Xcode Emulator, A Real iPhone and the result is always the same.

Also worth noting is that I'm using Capacitor, not Cordova. I've tried this in my capacitor.config.json but it had no effect.

 "iosScheme": "https",

Update:

So it turns out that it's because the app runs with the local urlScheme of capacitor:// rather than https:// and the development team at Ionic currently have no plans to rectify this. Is there any way to make the Payment Request Button appear in a non-https environment?

1 Answers

After a lot of back and forth with Stripe's support team, I finally came up with a solution. A lot of what they said is included in this answer (placed in blockquotes). I've also included a code example that will hopefully help make sense of it.

I'm absolutely aware this is quite complex but unfortunately when not using our official iOS SDK the process is quite involved, and as of right now we don't have any official support for cross-platform technologies like Ionic or React Native.

You must have an apple developer account, a merchant id and have a payment processing certificate uploaded to stripe (see steps 1->3 of https://stripe.com/docs/apple-pay#native)

You can use the cordova plugin (https://github.com/samkelleher/cordova-plugin-applepay#example-response) to generate an apple pay token. This will then be submitted to the V1 stripe API and exchanged for a Stripe Token. This is how Stripe's official IOS SDK works by tokenizing the PKPayment object in to a Stripe Token.

The paramaters to pass to the end point (not in the documentation) are;

  • pk_token (the string that you get from base64 decoding the paymentData)
  • pk_token_payment_netowrk (paymentMethodNetwork)
  • pk_token_instrument_name (paymentMethodDisplayName)
  • pk_token_transaction_id (transactionIdentifier)

The names in the brackets are what is returned when using the cordova plugin.

Once you call this endpoint, you should get back a standard Stripe token object(but the request will fail if you haven't registered your Apple Pay payment processing cert as mentioned above). The Stripe token(tok_xxx) can be used for payments as normal — the easiest way is to convert it to a PaymentMethod by calling /v1/payment_methods with type=card&card[token]=tok_xxxx , and then using it to confirm a PaymentIntent.

Code Example

completeApplePay(resp){
        const _this = this;

        return new Promise((resolution, rejection) => {
            $.post({
                url: 'https://api.stripe.com/v1/tokens',
                beforeSend: function (xhr) {
                    xhr.setRequestHeader("Authorization", "Bearer pk_test_xxxxxxxxxxxxxxxx")
                },
                data: {
                    pk_token: atob(resp.paymentData),
                    pk_token_payment_network: resp.paymentMethodNetwork,
                    pk_token_instrument_name: resp.paymentMethodDisplayName,
                    pk_token_transaction_id: resp.transactionIdentifier
                },
                success: function (data) {
                    resolution({
                       token: data.id
                    });
                }
            });
        });
    }

The (resp) parameter in the function above is the response from the cordova plugin;

const applePayTransaction = await this.applePayController.makePaymentRequest(order).then(resp => {
    this.stripe.completeApplePay(resp).then((stresp:any) => {
       // code goes here to store order in database etc
    })
});
await this.applePayController.completeLastTransaction('success');
Related