Recently I found myself putting together an Authorize.Net implementation for a client. For those who do not know, Authorize.Net
is a payment processing gateway similar to Verisign's Payflow Pro or the almost completely departed CyberCash's CashRegister.
Authorize.Net offers several different products and services ranging from a complete virtual terminal to payment forms. Unlike
several other gateways, the developer has the option of how to implement Authorize.Net's services. You can simply send the user
to a form on Authorize.Net's site (what they call WebLink), you can post your form to a page at Authorize.Net's site that will
grab a thank you page that you specify from your site and display to your users (what they call Relay Response), or you can use
3rd party software to post to their server and get the return values and then do what you need to in your script (what they call
Slow Out of the Gate
I have implemented CyberCash and Verisign's products several times before, but I had never done a project with Authorize.Net.
Several months ago in preparation for the payment portion of the project I am working on, I went to their site and found that
similar to other payment gateways they had a component, AuthNetSSLConnect, that you could download and install, which could be
used for passing your data to their site and getting the return values. Unfortunately, when I returned last week to gather all
the details, I realized that they no longer support the product and refer you to 3rd party solutions instead. After searching
the Internet for several hours and some of my favorite component sites, I realized that if I wanted to use someone's "3rd
party solution" I was either going to have to tell my client that I needed them to dish out some more money (which I'd
already done several times recently and was leery about doing again) or I could shell out the dough myself (which was
definitely not going to happen).
I went ahead and installed the version of AuthNetSSLConnect that I had downloaded previously hoping that it would still work.
After checking out the documentation that came with it and comparing it to the newest Developer's Guide from the site, it looked
like I was in luck. Alas, it was not meant to be and I got "memory out of range" errors when I ran it. I was ready
to give up and try something else.
Looks Promising? No it doesn't.
I thought I might try using the Relay Response that Authorize.Net offered and found that if you pass all the required parameters
- credit card number, expiration date, amount, etc. - the user would not even be shown any forms from Authorize.Net's site, but
instead sent directly to the thank you page after they processed the payment information. Worked well as far as I was concerned.
I did have a problem with it, though. Instead of redirecting them to your payment page they instead grab your page and display
it from their site. Yes, any code in the page is executed (like storing the information into a database), but what you are left
with is the user's browser open with a page served from the Authorize.Net site. I'm a smart guy and I probably could have
client's site, but at the time I didn't want to be encumbered with the mess. Plus with the applications that I am doing I
wanted a simple page that I could use as an include file that I could drop into any form handler page where I needed it and
it would work seamlessly into the process.
A Fresh Start
I was back to figuring out a way to post to their site from within my asp page and getting the return values all in the same
script. I knew that I could find a simple component out there to do it or I would just write one of my own. All of a sudden
it hit me - I remembered seeing some code for utilizing PayPal's direct response where the author was used Microsoft's XMLHTTP
to pass data to Paypal and get the return values.
I knew that Authorize.Net wasn't supporting XML yet, but I figured I would take a look at it anyway, maybe I would learn a thing
or two or I could make it fit. After playing around or awhile I tested to see if Authorize.Net would take the values in the
query string rather than in the content as a "POST" and it would. I was halfway there. An hour and a couple of
cups of coffee later and I found that I could pass the required values in the query string, send an empty string with the
Send method (normally used for sending XML), and when setting the proper parameters Authorize.net would send back the response
which I could assign to a variable with the XMLHTTP's responseText value. After some simple string manipulation and error
checking I was in business.
Following are code samples similar to what I did. The form page is based on the sample scripts I initially downloaded with
the AuthNetSSLConnect file.
'First enter our loginID
PostData = "x_Login=testdrive" 'test account for Authorize.Net
PostData = PostData & "&x_Version=3.0"
PostData = PostData & "&x_Test_Request=TRUE" 'since we are testing
PostData = PostData & "&x_ADC_Delim_Data=TRUE" 'we want comma delimited
PostData = PostData & "&x_ADC_URL=FALSE" 'do not want to redirect
'Now add the form fields
PostData = PostData & "&x_Card_Num=" & Request.Form("x_Card_Num") & ""
PostData = PostData & "&x_Exp_Date=" & Request.Form("x_Exp_Date") & ""
PostData = PostData & "&x_Description=" & Request.Form("x_Description") & ""
PostData = PostData & "&x_Amount=" & Request.Form("x_Amount") & ""
PostData = PostData & "&x_First_Name=" & Request.Form("x_First_Name") & ""
PostData = PostData & "&x_Last_Name=" & Request.Form("x_Last_Name") & ""
PostData = PostData & "&x_company=" & Request.Form("x_company") & ""
PostData = PostData & "&x_Address=" & Request.Form("x_Address") & ""
PostData = PostData & "&x_City=" & Request.Form("x_City") & ""
PostData = PostData & "&x_State=" & Request.Form("x_State") & ""
PostData = PostData & "&x_ZIP=" & Request.Form("x_ZIP") & ""
PostData = PostData & "&x_Phone=" & Request.Form("x_Phone") & ""
PostData = PostData & "&x_Fax=" & Request.Form("x_Fax") & ""
PostData = PostData & "&x_Email=" & Request.Form("x_Email") & ""
'Send the transaction info as part of the querystring
set xml = Server.CreateObject("Microsoft.XMLHTTP")
xml.open "POST", "https://secure.authorize.net/gateway/transact.dll?" _
& PostData & "", false
strStatus = xml.Status
strRetval = xml.responseText
set xml = nothing
'Response.Write "response = " & strRetVal & "<BR>" 'this will print out the
'entire return string
'first we'll create an array from the return value by splitting on the
'commas and then we'll assign each member of the array to values that
'better describe them for the reader. Of course we'd probably want to
'do something else with these values like save them to a database,
'create an email to send to the webmaster and/or the user
strArrayVal = split(strRetVal, ",", -1)
x_response_code = strArrayVal(0)
'1 = This transaction has been approved.
'2 = This transaction has been declined.
'3 = There has been an error processing this transaction.
x_response_subcode = strArrayVal(1)
x_response_reason_code = strArrayVal(2)
x_response_reason_text = strArrayVal(3)
x_auth_code = strArrayVal(4) '6 digit approval code
x_avs_code = strArrayVal(5)
'Address Verification system:
'A = Address (street) matches, Zip does not
'E = AVS error
'N = No match on address or zip
'P = AVS Not Applicable
'R = Retry, system unavailable or timed out
'S = service not supported by issuer
'U = address information is unavailable
'W = 9 digit Zip matches, address does not
'X = exact AVS match
'Y = address and 5 digit zip match
'Z = 5 digit zip matches, address does not
x_trans_id = strArrayVal(6) 'transaction id
x_invoice_num = strArrayVal(7)
x_description = strArrayVal(8)
x_amount = strArrayVal(9)
x_method = strArrayVal(10)
x_type = strArrayVal(11)
x_cust_id = strArrayVal(12)
x_first_name = strArrayVal(13)
x_last_name = strArrayVal(14)
x_company = strArrayVal(15)
x_address = strArrayVal(16)
x_city = strArrayVal(17)
x_state = strArrayVal(18)
x_zip = strArrayVal(19)
x_country = strArrayVal(20)
x_phone = strArrayVal(21)
x_fax = strArrayVal(22)
x_email = strArrayVal(23)
x_ship_to_first_name = strArrayVal(24)
x_ship_to_last_name = strArrayVal(25)
x_ship_to_company = strArrayVal(26)
x_ship_to_address = strArrayVal(27)
x_ship_to_city = strArrayVal(28)
x_ship_to_state = strArrayVal(29)
x_ship_to_zip = strArrayVal(30)
x_ship_to_country = strArrayVal(31)
x_tax = strArrayVal(32)
x_duty = strArrayVal(33)
x_freight = strArrayVal(34)
x_tax_exempt = strArrayVal(35)
x_po_num = strArrayVal(36)
x_md5_hash = strArrayVal(37)
'Check the ErrorCode to make sure that the component was able to talk
'to the authorization network
If (strStatus <> 200) Then
Response.Write "An error occured during processing. " _
& "Please try again later."
If x_response_code = 1 Then
Response.Write("Thank you for your purchase.")
elseif x_response_code = 2 then
Response.Write("The transaction was not approved: " _
response.Write "An error occured during processing. " _
& "Please try again later."
Success and Personal Validation
One thing that I was worried about, since I had never seen it done (or at least never noticed it) before was the security of passing values in the query string of the URL. I once again did some searching on the Internet and found this tasty gem from Netscape, the original designers of SSL:
"SSL provides a security "handshake" that is used to initiate the TCP/IP connection... this means that all the information in both the HTTP request and the HTTP response are fully encrypted, including the URL the client is requesting..."
My questions, along with my prayers, were answered - when using SSL passing the data in the query string is just as safe as passing it in the content body.
All in all, it wasn't a bad way to spend an evening:
I had found a way to query Authorize.Net.
My script was completely customizable and I could set it up so that it could be dropped in wherever I needed it.
It did not use any 3rd party components that I would have to fight to get installed on a hosting provider's server.
I might have found a way to use Microsoft's XMLHTTP component in which it's original designers may have never had intended.
And best of all - my solution was completely free.