Search code examples
javascriptasp.netwebformsbraintree

Braintree integration - cannot access javascript nonce in server side code


I'm using the Braintree dropin on an ASP.Net webform, and having trouble reading the nonce returned from javascript. It is being generated, but on my server side code I cannot access it. I suspect it's due to the server side code being called before the Javascript code completes, but as web development isn't my forte I'm not sure.

My client side code TestBrainTree.aspx:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="TestBrainTree2.aspx.vb" Inherits="eStore2.TestBrainTree2" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="utf-8">
  <script src="https://js.braintreegateway.com/web/dropin/1.16.0/js/dropin.min.js"></script>
</head>
<body>
   <form id="form1" runat="server"> 
       <div id="dropin-container"></div>
        <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="True"></asp:ScriptManager>  
          <button id="btnSubmit">Request payment method</button>
        <asp:label id="lblResult" runat="server"></asp:label>
    <input id="payment_method_nonce" name="payment_method_nonce" type="hidden" />
    </form> 
  <script>
    var button = document.querySelector('#btnSubmit');

    braintree.dropin.create({
      authorization: '<%=clientToken%>',
      container: '#dropin-container'
    }, function (createErr, instance) {
      button.addEventListener('click', function () {
        instance.requestPaymentMethod(function (err, payload) {
          // Submit payload.nonce to your server
            document.querySelector('#payment_method_nonce').value = payload.nonce;
            alert(document.querySelector('#payment_method_nonce').value);
         });
      });
    });
  </script>
</body>
</html>

The alert(document.querySelector('#payment_method_nonce').value); line shows that the nonce has been generated successfully. My server side code TestBraintree2.aspx.vb:

Imports Braintree

Public Class TestBrainTree2
    Inherits System.Web.UI.Page

    '#Region page variables
    Public clientToken As String
    '#endregion

    Private gateway As BraintreeGateway = New BraintreeGateway With {
        .Environment = Braintree.Environment.SANDBOX,
                    .PublicKey = "XXXX",
                    .PrivateKey = "YYYY",
                    .MerchantId = "ZZZZ"
    }

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        ClientScript.GetPostBackEventReference(Me, String.Empty)

        If Not IsPostBack Then
            clientToken = gateway.ClientToken.Generate()
        Else
            Dim nonce As String = Request.Form("payment_method_nonce")
            Dim request2 = New TransactionRequest With {
                .Amount = 10D,
                .PaymentMethodNonce = nonce
            }
            Dim result As Result(Of Transaction) = gateway.Transaction.Sale(request2)

            If result.IsSuccess() Then
                lblResult.Text = String.Format("<b>Transaction id:</b>{0}", result.Target.Id)
            Else
                lblResult.Text = "Error"
            End If
        End If
    End Sub

End Class

Have hidden my keys in the code above for security. The problem occurs in the Dim nonce As String = Request.Form("payment_method_nonce") line where I expect to see the nonce generated in the client side, but it is blank.


Solution

  • You're correct that the reason you don't see the nonce is because the form is submitted before you set the nonce.

    Change your frontend code to the following to resolve the issue. The code prevents the form from submitting until it gets a nonce. Once it gets the nonce it will submit the form automatically.

    <script>
      var form = document.querySelector('#form1');
    
      braintree.dropin.create({
        authorization: '<%=clientToken%>',
        container: '#dropin-container'
      }, function (createErr, instance) {
        form.addEventListener('submit', function (event) {
          event.preventDefault();
    
          instance.requestPaymentMethod(function (err, payload) {
            if (err) {
              console.log('Error', err);
              return;
            }
    
            // Add the nonce to the form and submit
            document.querySelector('#payment_method_nonce').value = payload.nonce;
            form.submit();
          });
        });
      });
    </script>