PCI Compliance Matters
You wouldn’t risk using a website that didn’t have a TLS certificate would you? ...exactly, and credit card payments are no different.
Every time you enter your card details into a websites payment form, you are theoretically risking submitting those details, in full, back to the server to be stored and used by anyone who has access to the back-end of that platform and it’s accompanying database.
Fortunately, there’s a method to help ensure you can provide a fully secure implementation when concerning this feature -
“The Payment Card Industry Data Security Standard (PCI DSS) is a set of security standards designed to ensure that ALL companies that accept, process, store or transmit credit card information maintain a secure environment.”
PCI DSS, aka "PCI Compliance" is the implementation that all online card payments should follow to ensure that your credit card details are not revealed to the people whom you are executing the payment to.
Stripe was founded in 2011 by the Collison brothers. Their platform allows you to accept credit card payments over the internet...and it doesn’t stop there. Stripe’s API is very clean, and their anti-fraud monitoring and analytical data goes far beyond the likes of their competitors.
It’s worth noting that Stripe actually pride themselves on being a “developers first” business...unsurprising, given both the founders are programmers at heart.
Card Payment Process Flow
Before we get started, it's worth highlighting that card payments are a complicated process will multiple permutations and potential exception points. Given this, I'll be coding a "happy path" scenario only for this example.
The first thing to do is pull in a copy of the Stripe.Net package from Nuget.
Once that's done, let's code our input and output data models for the view. Our input will need a token property for the authentication token we receive back from Stripe, and an email property so we can submit a receipt to our user.
Once a successful payment is made, we'll need to pull back some of the key data from the response object, in order to verify that the payment has gone through.
Now at this point, the Stripe card element's form will indeed generate a token for us, but a few amends are necessary in order for us to complete the payment process flow in full.
...The CardPaymentViewModel we created initially needs to be bound to the view and used to created two hidden fields for both the email address and the token properties.
Next, we need to code our service wrapper around the Stripe API. Here we make use of Stripe's ChargeService class, which we use to submit a ChargeCreateOptions object to and receive a Charge object back from.
There are a few key properties to highlight here. The ChargeCreateOptions object has a TransferGroup property which is an ID field that we can use for the payment transaction itself. The token we received initially will be assigned to the SourceId property, and the users email will be assigned to the ReceiptEmail property. Finally, we need to ensure that the Capture property is set to "true", so that the card is actually charged for the payment...
Next we need to map our payment receipt data. In an ideal world we would use AutoMapper, but for simplicity I've mapped this data by hand as follows.
Our service is coded, so let's inject it into our controller.
Now let's obtain the two necessary keys from your Stripe account dashboard - The secret key and the publishable key.
We then map our keys into our appsettings file.
Finally we can configure Stripe with our secret ApiKey and dependency inject our service.
Testing Our Credit Card Payments
Let's now test our implementation. Stripe supply a series of test card numbers for us to use. I'm specifically using the UK test numbers...
The first thing to try is an invalid card number, to see how Stripe's default client-side validation handles recognizing this at the point where we submit the payment.
Very cool right? Next let's use one of the valid test card numbers and see how the form changes.
...Note how the visa icon has appeared next to the card number, indicating that it's valid. Another thing to point out is that the postcode field has appeared (and if we chose to use an American test card number, this would actually say "Zipcode").
Finally let's submit fully valid details (a valid Stripe test card number and postcode, plus any values that you like for the expiry data and CVC number).
In this case, I chose to use the postcode of Westminster Abbey.
Our details look valid, so let's submit them and pay our £99 bill, with the hope of viewing a successful payment receipt back from Stripe.
...and there you have it, PCI Compliant credit card payments using the Stripe API and C# ASP.Net MVC Core!
We're Not Quite Finished...
Remember the Stripe dashboard that we hooked into earlier? Let's log back in and view our credit card payment transactions...
As you can see, Stripe identify the credit card payment as successful, and specifically being for the customer name we entered at the point of payment.
Next we can see that Stripe's risk evaluation for the credit card payment was classed as "normal".
Remember the description and the ID that we assigned to the TransferGroup field as part of the ChargeCreateOptions object when submitting the payment? As you can see, Stripe track this information with the payment, along with the postcode data we submitted. You can also see that Stripe's checks against the credit card CVC number and postcode were indeed successful.
The final interesting piece of data that is tracked by Stripe at the point of processing a PCI Compliant credit card payment, is the registering of he device IP Address that I used when submitting the payment, along with the operating system, browser and device type that I was running. Kinda scary...albeit necessary.
Download Github Code Sample
Feel free to DOWNLOAD the sample code of the aforementioned implementation from my Github account.