logo

Accept Payments with Stripe

- July 15, 2020

Photo by Joseph Barrientos

When you put payment on your site, you know that things get serious. Payment means you have something users are willing to pay. Payment is a barrier so you need to convince the user that it's worth it. If you provide a service that no else provide for free, then you can hope to sell it. The price is linked to the value of the service or the good.

Digital payment involves the use of credit card payment because it is simpler than a bank transfer and there is consumer protection through chargebacks. You don't reinvent the wheel and you use a payment processor. Stripe and Paypal are the main payment systems available.

The web client is an insecure place so you need another place to do the sensitive operations. Paypal and Stripe do the heavy lifting. The user sends his card details to Stripe or Paypal directly. His card number doesn't go through your own server. This removes security risks as you don't handle the sensitive information yourself. You bring the user to a Stipe managed interface and let him provide his bank details. Your only concern is to identify a user and react to the success or failure of the payment that will be communicated by the payment processor.

A payment starts with a payment intent

The payment process starts with a payment intent. The payment intent represents the will to pay a specific amount to a specific person. The recipient transmits that payment intent to stripe and gets a client secret in return. The "client secret" name is misleading because the client is not identified at that point. The client secret is merely a unique id representing the recipient secret key along with the intended amount of money. That client secret can be used by any cardholder to carry out the transaction.

The three parts structure

The general structure is divided in 3 parts

  • the client (web or mobile)

  • a trusted environment (a server or a serverless function)

  • the stripe server

Perform the sensitive actions on a trusted environment

The amount of the transaction is a critical data that must be protected from any possible alteration.

You provide the transaction details to Stripe through a HTTP request to the https://api.stripe.com/v1/payment_intents endpoint. As the request contains your secret key, Stripe is able to infer you are the recipient of the transaction. The request also contains the transaction amount.

You can't rely on the web client to do the HTTP request, as a malicious actor can change the secret key or change the transaction amount in the HTTP request, resulting in money loss.

You must perform the HTTP request on a trusted environment, unaccessible to malicious actors. This environment can be your own server or a "serverless" cloud function.

Don't collect the card information yourself

At some point in the process, the user must input its card details. You cannot take the responsibility to handle or store the card details yourself. It's too risky and a bad practice.

You delegate the card details collection to your payment processor. You must embed an iframe designed and controlled by the payment processor. This protected component collects and transmits the sensitive data directly to the payment processor server.

Stripe provides a set of React components called Elements. They look great and collect the card information gracefully. They prompt for the card information already stored in the browser to speed up the process. They also let you scan your credit card with your mobile camera.

React to the payment success

The web client displays a confirmation message to the user. Stripe notifies the backend that the payment is complete. The backend can act upon this success:

  • Send a confirmation email to the user

  • Notify admins

  • Create and send a receipt

  • Update the database

  • Grant user access to some content