ASP.NETHTML 5

Processing Payments and with Stripe, JavaScript and C# - PCI compliant

The source code and post have been updated to use the latest Stripe.NET API => v4.2

Online payments! We've all used them and some of us may have had the "fortune" implementing them on one website or another. [Stripe](http://stripe.com" target="_blank") is the not-so-new kid on the block, since it recently expanded in many countries, that makes this development task a breeze.

If you are using .NET, then [Stripe.NET](https://github.com/jaymedavis/stripe.net" target="_blank) is an excellent library that hides away most of the complexity and provides a very nice API. You can get it as a NuGet package or you can check the source code on GitHub. Although Stripe.NET is excllent, it comes with a big caveat: if you process the payment details on your server, then you need to be PCI compliant and you are bound to some really strict regulations. Yes, this applies even when you don't store Credit/Debit card information on your servers. The simple transmission of the data makes you liable to PCI legislation.

If you are PCI-compliant and still want to use the Stripe.NET exclusively to process payments, please check my post [here.](GHOST_URL/processing-payments-on-your-site-using-stripe-and-net/" target="_blank)

But fret not my friend, as there is a fairly simple solution : Stripe.js. This is the library provided by the lovely folks over at Stripe that allows you to process payment information and charge credit cards to your heart's content and still be PCI-compliant. By using the Stripe.js library, you can send the payment details (card number, cvc and expiry date) to Stripe directly from the javascript client and in return you get a token which you can use later to make a one off charge. The good news is that the payment details never make it to your server so you don't have to worry about the legal implications.

So, let's create an example to see all this in action.

1. The ASP.NET MVC View

We will create a basic MVC View which will be used to retrieve and process the payment details from the user.

@model StripeTest.Models.StripeChargeModel

@{
    ViewBag.Title = "Stripe Tutorial";
}

<h2>Stripe Charge Example with Stripe.js</h2>

<div>
    <h4>Stripe Charge Example</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            <label for="txtCardNumber">Card Number *</label>
        </dt>

        <dd>
            <input type="text" id = "txtCardNumber" placeholder="Card Number e.g 1234..." />
        </dd>

        <dt>
           <label for="txtCvc">Cvc *</label>
        </dt>

        <dd>
            <input type="text" id="txtCvc" placeholder="Security Code e.g 987" />
        </dd>

        <dt>
            <label for="txtExpiryMonth">Expiry Month (MM) *</label>
        </dt>

        <dd>
            <input type="text" id="txtExpiryMonth" placeholder="01" />
        </dd>

        <dt>
            <label for="txtExpiryYear">Expiry Year (YYYY) *</label>)
        </dt>

        <dd>
            <input type="text" id="txtExpiryYear" placeholder="2015" />
        </dd>
    </dl>
</div>
@using (Html.BeginForm("Charge", "Home", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post, new {@class = "form-horizontal", role = "form", id = "frmCharge"}))
{
    @Html.AntiForgeryToken()
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.CardHolderName)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.CardHolderName, new {id = "txtCardHolderName"})
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Amount)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.Amount, new {id = "txtAmount"})
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.AddressLine1)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.AddressLine1, new {id = "txtAddress1"})
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.AddressLine2)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.AddressLine2, new {id = "txtAddress2"})
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.AddressCity)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.AddressCity, new {id = "txtCity"})
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.AddressPostcode)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.AddressPostcode, new {id = "txtPostcode"})
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.AddressCountry)
        </dt>

        <dd>
            @Html.TextBoxFor(model => model.AddressCountry, new {id = "txtCountry"})
        </dd>
    </dl>
    <p>
        @Html.HiddenFor(model => model.Token, new { id = "hdnToken" })
        @Html.ActionLink("ProcessPayment", "Charge", null, new {id = "btnCharge"})
    </p>
}

View StripeView.cshmtl on GitHub

The View, we will name it Charge.cshtml for now, is a boiler plate input form. The interesting part is that the view is logically split into two sections with some input elements inside the form and some elements outside the form. The reason for this is that the input elements outside the form will not be posted back to the server when we submit the form, hence making the process PCI-compliant.

The View has a strongly typed model StripeChargeModel, to pass the data to and from the controller. It is highly recommended that you add validation using your preferred way to ensure that the data entered has the right format and it's valid - e.g. ExpiryDate set in the past or not a valid date etc.

Now, at the bottom of the page, add the JavaScript code to get the Stripe token and submit the form. I am using a view with a layout so my Javascript is inside a section. In addition to the imported .js libraries on this page, the layout page also includes a reference to jQuery, so make sure you add it to your page as well if not already available.

@section Scripts {
    <script type="text/javascript" src="https://js.stripe.com/v2/"></script>

    <script type="text/javascript">
        $('document').ready(function() {
            Stripe.setPublishableKey('Your Publisheable Key Goes here');

            $('#btnCharge').on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                Stripe.card.createToken({
                    number: $('#txtCardNumber').val(),
                    cvc: $('#txtCvc').val(),
                    exp_month: $('#txtExpiryMonth').val(),
                    exp_year: $('#txtExpiryYear').val()
                }, stripeResponseHandler);
            });

            function stripeResponseHandler(status, response) {
                var $form = $('#frmCharge');

                if (response.error) {
                    // Show the errors on the form
                    alert(response.error.message);
                } else {
                    // response contains id and card, which contains additional card details
                    var token = response.id;
                    // Insert the token into the form so it gets submitted to the server
                    $('#hdnToken').val(token);
                    // and submit
                    $form.get(0).submit();
                }
            }
        });
    </script>
}

View stripeJavaScriptCode.js on GitHub

Let's break down the code, shall we?

First we add a reference to the the Stripe.js file and then inside the document.ready() we set our Publisheable key. You can get your public key from the Stripe dashboard. Then we create an event handler for the button click and a callback method stripeResponseHandler(). The 'click' event handler is responsible for retrieve the Credit/Debit card details and posting them directly to Stripe in order to get a Token. Notice that we use the minimum information necessary in order to retrieve the Token. Once that call is successful, Stripe sends a response which we process in the stripeResponseHandler() callback method. If the response has an error, e.g. due to invalid credit card number etc, then we alert the user with the error message. If the response is successful, we save the Token value to a hidden field and then submit the form to the server with the rest of the details in order to charge the user's card.

NOTE: the current code contains no validation. You should definitely implement validation to ensure that users enter valid data and provide a great user experience by giving feedback accordingly.

2. The DataModel

The DataModel is used to pass data between the view and the controller. The model attached below is a very crude one and doesn't contain any validation other than setting the Amount and the Token properties to mandatory. I would argue that the CardHolderName should also be made mandatory/required as it will show up on the Stripe Dashboard when running reports etc.

using System.ComponentModel.DataAnnotations;

public class StripeChargeModel
{
	[Required]
	public string Token { get; set; }

	[Required]
	public double Amount { get; set; }

	// These fields are optional and are not 
	// required for the creation of the token
	public string CardHolderName { get; set; }
	public string AddressLine1 { get; set; }
	public string AddressLine2 { get; set; }
	public string AddressCity { get; set; }
	public string AddressPostcode { get; set; }
	public string AddressCountry { get; set; }
}

View stripeDataModel.cs on GitHub

3. The controller

The controller contains two methods, the first is the GET and the second is the POST. The first one doesn't do anything other than serve the View with the corresponding model. The second, on the other hand, validates the model and makes the Credit/Debit card charge.

public ActionResult Charge()
{
	ViewBag.Message = "Learn how to process payments with Stripe";
	return View(new StripeChargeModel());
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Charge(StripeChargeModel model)
{
	if (!ModelState.IsValid)
	{
		return View(model);
	}

	var chargeId = await ProcessPayment(model);
    // You should do something with the chargeId --> Persist it maybe?
    
	return View("Index");
}

private static async Task<string> ProcessPayment(StripeChargeModel model)
{
    return await Task.Run(() =>
    {
        var myCharge = new StripeChargeCreateOptions
        {
            // convert the amount of £12.50 to pennies i.e. 1250
            Amount = (int)(model.Amount * 100),
            Currency = "gbp",
            Description = "Description for test charge",
            Source = new StripeSourceOptions{
                TokenId = model.Token
            }
        };
    
        var chargeService = new StripeChargeService("your private key here");
        var stripeCharge = chargeService.Create(myCharge);
    
        return stripeCharge.Id;
    });
}

View StripeController.cs on GitHub

Pay close attention to the ProcessPayment() helper method that performs the actual charge with Stripe. We create a StripeChargeCreateOptions object with the amount and currency and StripeSourceOptions which contains the token. Then we create an instance of a StripeChargeService where we pass our private stripe key. The service is used to make the charge by calling the chargeService.Create(myCharge); method. This method returns a StripeCharge object which you can again persist or discard as you please.

This implementation ensures that any payment processed through your site is PCI-compliant. Stripe's simple and awesome!

You can check the full working source code on this [GitHub repo](https://github.com/cmatskas/StripeSample" target="_blank).

I hope this post made your life a little bit easier.