question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

paymentSecureConfirm mutation error using Stripe gateway

See original GitHub issue

Hello,

I’m trying to implement 3D secure flow with Stripe and I can’t manage to complete the checkout with cards that require authentication.

I’m trying to call the paymentSecureConfirm mutation after completing the 3D secure iframe confirmation step but this error shows up in server console:

web_1     | ERROR saleor.payment.gateway Error encountered while executing payment gateway. [PID:100:Thread-8]
web_1     | Traceback (most recent call last):
web_1     |   File "/app/saleor/payment/gateway.py", line 212, in _fetch_gateway_response
web_1     |     response = fn(*args, **kwargs)
web_1     |   File "/app/saleor/extensions/manager.py", line 250, in confirm_payment
web_1     |     return self.__run_payment_method(gateway, method_name, payment_information)
web_1     |   File "/app/saleor/extensions/manager.py", line 330, in __run_payment_method
web_1     |     raise Exception(
web_1     | Exception: Payment plugin Stripe for confirm_payment payment method is inaccessible!

Thanks in advance

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
keanesfcommented, Jan 1, 2021

Are there any current plans to add support for Stripe 3D Secure authentication in 2021 ?

3reactions
nik-scommented, Jan 13, 2020

Apologies for not providing enough details at the start. I just revisited all the steps I followed to implement the checkout and I actually ran into a few more problems along the way. I’ll create separate issues if needed.

My front-end is built with React and Apollo. These are the steps I followed:

1. Create checkout object and update shipping method

No issues here:

View mutations
# Create checkout
mutation(
    $email: String!
    $shippingAddress: AddressInput!
    $billingAddress: AddressInput!
    $lines: [CheckoutLineInput]!
  ) {
  checkoutCreate(
    input: {
      email: $email
      shippingAddress: $shippingAddress
      billingAddress: $billingAddress
      lines: $lines
    }
  ) {
    checkout {
      id
      token
    }
    errors {
      field
      message
    }
  }
}
# Get ids of available shipping methods
query($checkoutToken: UUID!) {
  checkout(token: $checkoutToken) {
    availableShippingMethods {
      id
    }
  }
}
# Update checkout shipping method and get available payment gateways
mutation($checkoutId: ID!, $shippingMethodId: ID!) {
  checkoutShippingMethodUpdate(
    checkoutId: $checkoutId
    shippingMethodId: $shippingMethodId
  ) {
    checkout {
      totalPrice {
        gross {
          amount
          currency
        }
      }
      availablePaymentGateways {
        name
        config {
          field
          value
        }
      }
    }
    errors {
      field
      message
    }
  }
}

2. Create Stripe token, create payment object and complete checkout

Below is a simplified version of my React component, for brevity’s sake I removed all error handling.

import React from 'react'
import { CardElement, injectStripe } from 'react-stripe-elements'
import { useMutation } from '@apollo/react-hooks'
import { gql } from 'apollo-boost'

const CHECKOUT_PAYMENT_CREATE = gql`
  mutation($checkoutId: ID!, $token: String!, $amount: Decimal!) {
    checkoutPaymentCreate(
      checkoutId: $checkoutId
      input: { gateway: "Stripe", token: $token, amount: $amount }
    ) {
      payment {
        id
        chargeStatus
      }
    }
  }
`

const CHECKOUT_COMPLETE = gql`
  mutation($checkoutId: ID!) {
    checkoutComplete(checkoutId: $checkoutId) {
      order {
        id
        status
      }
    }
  }
`

const CheckoutPaymentForm = ({ amount, checkoutId, stripe }) => {
  const [createPayment] = useMutation(CHECKOUT_PAYMENT_CREATE)
  const [checkoutComplete] = useMutation(CHECKOUT_COMPLETE)

  const handleSubmit = async e => {
    e.preventDefault()

    const { token } = await stripe.createToken()

    createPayment({
      variables: {
        checkoutId,
        amount,
        token: token.id,
      },
    }).then(() => {
      checkoutComplete({
        variables: {
          checkoutId,
        },
      })
    })
  }

  return (
    <form onSubmit={handleSubmit}>
      <CardElement hidePostalCode />
      <button type="submit">PAY</button>
    </form>
  )
}

export default injectStripe(CheckoutPaymentForm)

When the user inserts a credit card number into the card input rendered by react-stripe-elements and hits submit, a token is created by stripe.createToken(). This token is passed to the checkoutPaymentCreate mutation. If there are no errors the component calls the checkoutComplete mutation to create the charge on the user’s credit card.

However this error shows up in the server console after running checkoutComplete:

web_1     | INFO stripe message='Request to Stripe api' method=post path=https://api.stripe.com/v1/payment_intents [PID:9:Thread-8]
web_1     | INFO stripe message='Stripe API response' path=https://api.stripe.com/v1/payment_intents response_code=400 [PID:9:Thread-8]
web_1     | INFO stripe error_code=None error_message='A token may not be passed in as a PaymentMethod. Instead, use payment_method_data with type=card and card[token]=tok_1G0Z1PDPP6tn2u4HVCUtgOa2.' error_param=payment_method error_type=invalid_request_error message='Stripe API error received' [PID:9:Thread-8]

The error is caused by the following code in this file:

https://github.com/mirumee/saleor/blob/master/saleor/payment/gateways/stripe/init.py#L48

The error goes away if I replace payment_method with a payment_method_data object like this:

intent = client.PaymentIntent.create(
    payment_method_data={
        "type": "card",
        "card": {
            "token": payment_information.token
        }
    },
    amount=stripe_amount,
    currency=currency,
    confirmation_method="manual",
    confirm=True,
    capture_method=capture_method,
    setup_future_usage=future_use,
    customer=customer_id,
    shipping=shipping,
)

After making this change I’m able to complete the checkout succesfully with a credit card that doesn’t require authentication such as this one: 4242 4242 4242 4242 (Stripe test card numbers.) The order shows as fully paid in Saleor dashboard and the charge is successful in the Stripe dashboard.

However, the charge is not working with a card that requires 3D Secure authentication such as this one: 4000 0027 6000 3184. It incorrectly shows up as fully paid in Saleor dashboard, while it is displayed as incomplete in Stripe dashboad as the auth step has not been completed.

According to Stripe docs, a PaymentIntent requires a an authentication step if its next_action is redirect_to_url. I was able to get this info by turning off Automatic payment capture in dashboard and inspecting the gatewayResponse JSON object returned by checkoutComplete mutation (I’m not able to find redirect_to_url if auto capture is enabled):

mutation($checkoutId: ID!) {
  checkoutComplete(checkoutId: $checkoutId) {
    order {
      payments {
        id
        transactions {
          kind
          gatewayResponse
        }
      }
    }
  }
}

Also, according to the Stripe docs a return_url must be set up for the redirect step. For now I just hard coded it in the authorize function in the __init__.py file I mentioned before:

intent = client.PaymentIntent.create(
    payment_method_data={
        "type": "card",
        "card": {
            "token": payment_information.token
        }
    },
    amount=stripe_amount,
    currency=currency,
    confirmation_method="manual",
    confirm=True,
    capture_method=capture_method,
    setup_future_usage=future_use,
    customer=customer_id,
    shipping=shipping,
    return_url="http://localhost:8001/checkout/confirmation",
)

Afterwards, using the info in gatewayResponse I’m able to create an iframe such as the one in the docs with the 3D Secure UI and complete the authentication step.

However, if I try to call the paymentSecureConfirm mutation after completing the 3D Secure auth this exception comes up in the server console:

Exception: Payment plugin Stripe for confirm_payment payment method is inaccessible!

Please tell me if you need any additional details, Thanks

Read more comments on GitHub >

github_iconTop Results From Across the Web

paymentSecureConfirm mutation error using Stripe gateway
I'm trying to call the paymentSecureConfirm mutation after completing the 3D secure iframe confirmation step but this error shows up in server ...
Read more >
Saleor/CHANGELOG and Saleor Releases (Page 7) | LibHunt
A modular, high performance, headless e-commerce platform built with Python, ... and update order and payment fields; drop PaymentSecureConfirm mutation, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found