Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stripe Strong Customer Authentication #330

Closed
manikkang opened this issue Jul 30, 2019 · 17 comments · Fixed by #355
Closed

Stripe Strong Customer Authentication #330

manikkang opened this issue Jul 30, 2019 · 17 comments · Fixed by #355

Comments

@manikkang
Copy link

Stripe Api uses new methods for creating the charge. Has the gem being updated to accordingly?

@dyerc
Copy link

dyerc commented Aug 12, 2019

I've just been investigating this myself. It looks as though spree_gateway doesn't currently support this. It supports v3 of the Stripe api, but still uses the old methods for creating a token and active merchant to process the payment. This doesn't work for supporting 3D secure which appears to by default require using Stripe payment intents functions. I could be wrong, this is how I interpreted it.

There is a pull request for active merchant which seems to support the new Stripe payment intents api (activemerchant/active_merchant#3290).

Once this is merged into active merchant, this gem will need updating to use the new functionality. I'm hoping this will enable support for SCA and 3D Secure, I guess by redirecting the user to the 3D secure confirmation page?

It would be really helpful to have an update from someone who knows more about the spree_gateway gem, because the deadline is just over a month away. I'm happy to help writing a pull request.

@waaux
Copy link

waaux commented Aug 19, 2019

Few days ago Active Merchant added the new gateway Stripe Payment Intents to support SCA and 3D Secure. Is anyone working on updating this gem to be able to use this gateway??

https://github.com/activemerchant/active_merchant/blob/master/lib/active_merchant/billing/gateways/stripe_payment_intents.rb

@damianlegawiec
Copy link
Member

Hey @dyerc @waaux we're always happy reviewing and merging PR with this feature, thanks!

@imotion-software
Copy link

Any news about Stripe Payment Intents API implementation?
In Europe it's mandatory since September...

@AnkurVyas-BTC
Copy link

@damianlegawiec @dyerc @manikkang - Any update on this?

@damianlegawiec
Copy link
Member

@AnkurVyas-BTC you can track progress here: #355

@AnkurVyas-BTC
Copy link

@damianlegawiec - Cool 👍

@weefunker
Copy link

Any word on this being updated? I just got an email from Stripe warning that payments are going to be declined

@satyakam-nividata
Copy link

Any updates about when this PR #355 will be merged?

@mvanio
Copy link

mvanio commented Jul 31, 2020

Are we there yet? #355 seems complete or am I wrong?

@eduardstinga
Copy link

I'm interested in an update as well

@satyakam-nividata
Copy link

satyakam-nividata commented Oct 20, 2020

Hello @damianlegawiec In pull request mentioned above #355 we only give support for processing payments using Stripe's PaymentIntent in Spree UI. Are we going to add support for Spree Storefront API V2 too? I'm working on a project which requires SCA supported payments. I'm no expert here, but it'll be great if you can lead me in the right direction.

Currently, I tried to use the code of #355 PR, and I can easily process normal payments by using Stripe's createToken method. But it seems that the method doesn't support SCA. So now, I'm wondering how to make it work with Stripe's PaymentMethod creation method.

I'm using https://github.com/spree/spree-storefront-api-v2-js-sdk and stripe/react-stripe-js v1.1.2 and stripe/stripe-js v1.5.0

Here's the code snippet.
`const result = await stripe.createPaymentMethod({
type: 'card',
card: elements.getElement(CardElement),
billing_details: { name: 'ABC XYZ' }
});

if (!result.error) {
const order = {payments_attributes: [{payment_method_id: '7'}]};
const { userAddress } = getState();
const { firstname, lastname } = userAddress;
const { exp_year, exp_month, last4 } = result.paymentMethod.card;
const paymentSource = {'7': { gateway_payment_profile_id: result.paymentMethod.id, number: last4, month: exp_month, year: exp_year}};
const response = await client.checkout.orderUpdate({ bearerToken: token }, {...params, include: 'payments'});
// Here I get error from backend server, that it cannot
}`

And in the backend, I get below error message.

Spree::Core::GatewayError at /api/v2/storefront/checkout

You cannot supply a PaymentMethod ID as the source parameter. Please use the payment_method parameter instead. If you wish to set a default payment method for this Customer for future Invoices, set invoice_settings.default_payment_method.

Thanks.

@satyakam-nividata
Copy link

I believe #355 handles all Spree UI stuff. I need to make it work for API V2, so it'll be great if you can lead me in the right direction. @damianlegawiec

@satyakam-nividata
Copy link

I believe #355 handles all Spree UI stuff. I need to make it work for API V2, so it'll be great if you can lead me in the right direction. @damianlegawiec

I found the solution. Thanks for implementing Stripe SCA.

@damianlegawiec
Copy link
Member

@satyakam-nividata could you share that solution? Yes, our plan is to have this also in the headless API mode as well

@satyakam-nividata
Copy link

Here's how I managed to make it work in API mode.
In frontend code, I've added Stripe's CardElement, configured it in the checkout form.

const result = await stripe.createToken(elements.getElement(CardElement), { name: 'First Name + Last Name', });

I used result.token.id in the below code.

` const { token } = nextCookie({});

const payment = await client.checkout.paymentMethods({
bearerToken: token,
});

if (payment.isSuccess()) {
const { id } =
payment
.success()
.data.find(
item =>
item.attributes.type === 'Spree::Gateway::StripeElementsGateway',
) || {};
const order = {
payments_attributes: [
{
payment_method_id: id,
},
],
};

const paymentSource = { [id]: { gateway_payment_profile_id: result.token.id } };

const checkout3 = await dispatch(
  orderUpdate({ order, payment_source: paymentSource }),
);
// I'll add below Axios call to Spree sdk 
const pc_data = await axios.patch(
  `https://localhost:3000/api/v2/storefront/checkout/payment_confirm`,
  { access_token: token },
);

if (pc_data.data.client_secret) {
  const ccp_resp = await stripe.confirmCardPayment(
    pc_data.data.client_secret,
    {},
  );

  // I'll add below Axios call to Spree sdk 
  const hr_data = await axios.patch(
    `https://localhost:3000/api/v2/storefront/checkout/handle_response`,
    { access_token: token, response: ccp_resp },
  );

  if (!hr_data.data.success) {
    dispatch(handlePaymentFailure());
    toast.error(<ToastError>Payment declined.</ToastError>);
    dispatch(updateCheckoutStatus('error'));
    return;
  }
}

// Order complete
const complete = await client.checkout.complete(
  { bearerToken: token },
  {
    include: 'variants',
    fields: orderCompleteFields,
  },
);

`

I added 2 methods in CheckoutControllerDecorator

`module MyProject
module CheckoutControllerDecorator

def payment_confirm
  spree_authorize! :update, spree_current_order, order_token

  if spree_current_order.intents?
    spree_current_order.tap do |order|
      order.process_payments!
      order.reload.payments.valid.where.not(intent_client_key: nil).last.tap do |payment|
        client_secret = payment.intent_client_key
        pk_key = payment.payment_method.preferred_publishable_key
        render json: {client_secret: client_secret, pk_key: pk_key}, status: :ok and return
      end
    end
  end

  render json: {client_secret: '', pk_key: ''}, status: :ok
end

def handle_response
  spree_authorize! :update, spree_current_order, order_token

  if params['response']['error']
    payment = spree_current_order.payments.find_by!(response_code: params['response']['error']['payment_intent']['id'])
    payment.update(state: 'failed', intent_client_key: nil)
    render json: {success: false}, status: :ok
  else
    render json: {success: true}, status: :ok
  end
end

end
end

Spree::Api::V2::Storefront::CheckoutController.prepend MyProject::CheckoutControllerDecorator
`

In routes.rb

namespace :api do namespace :v2 do namespace :storefront do resource :checkout, controller: :checkout, only: %i[update] do patch :payment_confirm patch :handle_response end end end end

I think it's good to go. Any suggestions are much appreciated.

@satyakam-nividata
Copy link

Hello @damianlegawiec, Any suggestions for the above solution?
And it creates customers in stripe per order. Is it normal? I think we should assign only one Stripe customer to Spree::User rather than having multiple stripe customers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants