Tutorial - A complete 3-D Secure Integration & Payment Processing Solution.
By Lance Robinson - Technology Evangelist, /n software,
Requirements: /n software E-Payment Integrator
Download Demo: Included in the installation of /n software E-Payment Integrator
Contents
- Introduction
- What is 3-D Secure?
- Visa, MasterCard, JCB, and URLs
- Eligible Card Ranges
- Verifying Customer Enrollment
- Payer Authentication Request (PAReq)
- Payer Authentication Response (PARes)
- Authorization
- Testing
Introduction
In this document we will demonstrate how to integrate the 3-D Secure services Verified By Visa, MasterCard SecureCode, and JCB
J/Secure into a merchant order page. We'll do this by using
the ThreeDSecure component included in /n software E-Payment Integrator to authenticate cardholders. This particular example uses the /n software E-Payment Integrator
.NET edition to create an ASP.NET solution, but the same functionality can be performed using the ASP Edition (classic asp),
the Java Server Edition (jsp), or even the C++ Edition (cgi).
Next, we'll go over setting up an account with Visa's PIT test server. Finally, we'll show how to pass on the 3-D Secure authentication tokens
during the credit card authorization process. Note that although our 3-D Secure component is certified and has gone through interoperability testing with
Visa, every merchant that signs up for 3-D Secure (whether they develop the application themselves, use a certified component, or buy
an off-the-shelf solution) is required to complete PIT testing.
What is 3-D Secure?
3-D Secure is a protocol developed by Visa to make online payments more secure through password authentication and cardholder
verification. Visa has licensed this technology out to other major credit card brands, giving us Verified By Visa, MasterCard SecureCode,
and JCB J/Secure. All three of these 3-D Secure services are supported by the /n software 3-D Secure MPI component. Here are the basics
of how 3-D Secure works:
In order for a cardholder to be able to use the service, they must enroll, at which time they set a password. Information about the cardholder is then created in Visa's (or MasterCard's, or JCB's) "Enrollment Server",
which keeps track of cardholders participating in the 3-D Secure service, and in the Access Control Servers (ACS), which are used at the
time of purchase to verify cardholder enrollment. After enrollment, the cardholder is eligible to take advantage of 3-D Secure
services offered by online merchants.
At the time of purchase, the merchant plug-in interface (MPI - i.e., the /n software E-Payment Integrator's ThreeDSecure component) contacts a "Directory Server"
to check for enrollment. If the cardholder is enrolled, the directory will respond back with the URL of an Access Control Server (ACS)
which can be used to authenticate the cardholder.
Next, the merchant sends a payer authentication request (PAReq) to the ACS through the cardholder's browser/device (important: this
request comes FROM the cardholder's computer - NOT from the merchant). Then the ACS will communicate directly with the cardholder (the
merchant is not involved in this part of the process) in order to authenticate the cardholder's password. After this, the ACS will send a signed
payer authentication response (PARes) to the MPI containing results of the cardholder authentication. Finally, the MPI will verify the ACS signature on the PARes, and parse the response, which
will contain information confirming the cardholder's authentication. At this point, the merchant continues with the normal credit card
authorization process, the only difference is that when the customer's credit card information is sent for authorization, the merchant
can submit additional values returned in a successful 3-D Secure authentication: XID (transaction Id), ECI (electronic commerce
indicator), and CAVV (cardholder authentication verification value). Submitting these values is required in order to qualify for
the protections and discounted rates that 3-D Secure transactions guarantee.
Visa, MasterCard, JCB, and URLs
The same code you write for Visa will also work for MasterCard and JCB, except you'll use different property values depending on which
card brand is in use. These values will be provided by the merchant's acquiring bank when the account is setup for VbV, SecureCode, or J/Secure.
When the customer presents his or her card, we'll examine it to find out what kind it is (Visa, MasterCard,
JCB, etc). Most credit card processing software will do this for you (for example, all of the
E-Business Integrator products that are for credit card payments ship with a CardValidator component, which determines the card type and
performs validation algorithms.
Once we know what kind of card it is, we can set up the MPI for use with Visa, MasterCard, or JCB. The only things you will need to
change depending on the card type are:
- DirectoryServerURL
The DirectoryServerURL property should be set to the URL of the directory server provided to you by Visa, MasterCard, or JCB. This
URL is used by the RequestCardRanges and VerifyEnrollment methods of the component.
- SSLAcceptServerCertEncoded
Setting the SSLAcceptServerCertEncoded property is optional, since the SSLServerAuthentication event could also be used (except in classic ASP).
If it finds any issues with the certificate presented by the server, the component will normally terminate the connection with an error.
You can override that behavior by setting this property to the base64 encoded public key of the certificate to trust. This value is
compared with the certificate presented by the server during SSL negotiation, and if they match, the server certificate is accepted and
the connection will continue normally. Alternatively, you can also override the certificate authentication by setting the SSLServerAuthentication event's Accept parameter to true or false.
- RootCertificate
The RootCertificate property is used to verify the digital signature of the payer authentication response when it is passed to
the CheckAuthenticationResponse method. It should be set to the base64 encoded public key value of the certificate to verify with. There
may be more than one possible signing certificate, so you can append to the RootCertificate property (instead of overwriting) by
prepending a "+" character to the base64 encoded string value, as shown in a later example in this tutorial.
- Client Certificate Properties
SSLCert must be set to point to the SSL client certificate required for authenticating yourself to the
directory and access control servers during SSL negotiation.
- You may also need to change the merchant number and password as well, if they are different between the various card brands.
Other information provided to the merchant by the acquiring bank are the merchant number (id) and password, certificates for signature verification, graphics, and client certificates (if applicable). The graphics (Visa, MasterCard, or JCB graphics) can be displayed on your websites to show that you are able to use 3-D Secure Authentication. The client certificate is not necessarily required - this depends on your location. Your acquiring bank will let you know which type of authentication you need to use when you sign up with them (either a password or a client certificate).
Eligible Card Ranges
Not all credit cards are eligible for 3-D Secure authentication, such as some check cards, gift cards, and corporate cards. To find out if a card
is eligible, you can download a list of eligible card ranges from the server, and check those ranges to see if the card in question is included. This step is optional, but is useful to avoid unnecessary authentication attempts.
The RequestCardRanges method of the 3-D Secure component sends a "Card Range Request" to the directory server. The response to this
request contains a list of card number ranges that are eligible for 3-D Secure enrollment. If the card number presented by the customer
falls within one of these ranges, the customer
might be enrolled in 3-D Secure service, but the VerifyEnrollment method needs to be used to
find out for sure (code sample below). If the customer card number does not fall within any of these ranges, then you know the customer is definitely not
enrolled in 3-D Secure, and regular credit card authorization should continue on without any 3-D Secure authentication.
After the RequestCardRanges method returns, the component's CardRanges collection will be
populated with the ranges. RequestCardRanges can either return all eligible card ranges, or it can return the
changes in
eligible card ranges since a previous request. This behavior is controlled by the SerialNumber property. If the SerialNumber property
has a value of "" (empty string) before calling RequestCardRanges, the full list of eligible card ranges will be returned. If the SerialNumber property has a non-empty value prior
to calling the RequestCardRanges method, then only the changes since the last response matching the specified SerialNumber will be returned.
So you can send a request for the full list, save the results, and then for subsequent card range requests you can simply get the changes and
update your saved list of ranges. This allows you to avoid downloading a large list of eligible card ranges too often, but it is recommended
that you refresh your local cache with a full list periodically.
For example,
CardRanges[0].Begin and CardRanges[0].End may be one range of eligible card numbers. If CardRanges[0].Action is "A", the cards in that range
are eligible. If CardRanges[0].Action is "D", the cards in that range are no longer eligible and should be deleted from any locally saved
cache of card ranges.
Verifying Customer Enrollment
To find out for sure if a cardholder is enrolled in a 3-D Secure service like Verified By Visa or MasterCard SecureCode, we use the VerifyEnrollment method of the ThreeDSecure component. When the VerifyEnrollment method returns, the
CardEnrolled property will have one of the values "Y" (yes, they are enrolled), "N" (no, they are not enrolled), or "U" (yes, they are enrolled,
but authentication is currently unavailable). If the CardEnrolled value is "Y", we can continue with 3-D Secure authentication and verify
the cardholder. Otherwise, we go back to regular credit card authorization without 3-D Secure authentication. Note that many US card issuers automatically enroll cards in 3-D Secure programs, so this may return "Y" unexpectedly. In this case, the card is enrolled even if the cardholder hasn't set a password, the issuing bank will behave appropriately when the payer authentication request is sent to them, and the payer authentication response will contain a specific ECI value that means the merchant attempted to authenticate - giving the merchant chargeback protection.
13DS.CardNumber = tbCardNumber.Text;
23DS.DirectoryServerURL = "https://<url.obtainedfrom.acquiringbank>/";
33DS.VerifyEnrollment();
4if (3DS.CardEnrolled == "Y")
5{
6 SendAuthenticationRequest();
7}
8//else the customer is not enrolled
In the example above, if the customer is enrolled we'll go on to the next step of 3-D Secure authentication: sending an authentication request.
Payer Authentication Request
The next step of a 3-D Secure authentication is to send a payer authentication request (PAReq) to an access control server (ACS). The URL of the ACS that we'll post to was provided to us in the
response to the VerifyEnrollment method, and is already stored and ready to use in the ACSURL property of the component.
In order to send the payer authentication request to the 3-D secure service, first we'll need to generate it. The component will do
this for you with the GetAuthenticationPacket method, which uses the properties of the component to generate a compressed and encoded
payer authentication request. Prior
to calling GetAuthenticationPacket, you'll need to set at least the MessageId, TransactionId, TransactionAmount, TransactionDisplayAmount, and the card properties:
13DS.MessageId = "11292007120208046";
23DS.TransactionId = "11292007120208046";
33DS.CardNumber = tbCardNumber.Text;
33DS.CardExpMonth = tbCardExpMonth.Text;
43DS.CardExpYear = tbCardExpYear.Text;
53DS.TransactionAmount = "7256";
63DS.TransactionDisplayAmount = "$72.56";
7string PAReq = 3DS.GetAuthenticationPacket();
Notice the transaction amount, on line 5 in the code sample above, is specified without a decimal point ($72.56 is represented as 7256).
Besides the payer authentication request, we also need to send two other pieces of data: "TermUrl" and "MD". TermUrl (termination URL) is the URL that
we want the ACS to post back to after it has authenticated the user. MD is the "merchant data" that we want the ACS to include in its
response back to us so that we can match their response to our sale. Typically this would be some unique identifier associated with the
transaction we're about to authorize (note that you should never send the card number in the MD field on a production system). For this
example, the MD will be a key into a database where we'll store the transaction information temporarily (while we await the response from the ACS).
The transaction information we need to store is exactly the same information used to generate the payer authentication request
(MessageId, TransactionId, CardNumber, TransactionAmount). Note: when storing data, be sure to follow payment application best practices. For more information
on CISP and PABP, see the /n software E-Payment Integrator documentation.
Next, we need to send the request, TermUrl, and MD to the access control server (ACS). Important: the request must be
sent through the cardholder's browser, and thus cannot be sent by the ThreeDSecure component itself. Instead, you must handle sending
the request yourself. One way to do this is with javascript, like so::
1myForm.Controls.Clear();
2ClientScript.RegisterHiddenField("PAReq", PAReq);
3ClientScript.RegisterHiddenField("TermUrl", Request.Url.Authority +
4 "/3dsResponse.aspx";);
5ClientScript.RegisterHiddenField("MD", mytransactionkey);
6myBody.Attributes.Add("onLoad", "javascript: document." + myForm.ID +
7 ".action='" + 3DS.ACSURL + "'; document." +
8 myForm.ID + ".submit();");
The above sample code will write the javascript code to the html page body, setting the action of the HTML form named "myForm" (the form where
the cardholder submitted their data) to the ACSURL, and submitting the form. Note that it adds three hidden fields that will be submitted
to the ACS URL: PAReq, TermUrl, and MD.
Please note that the above Javascript code, or something similar, is essential
to the way 3-D Secure works. The customer must be redirected from
his own browser window. The customer leaves the merchant's site and goes to the
location specified in the ACSURL property. After the customer inputs the
password for his credit card, he will be redirected back to the TermUrl,
on the merchant's server. The Merchant Data, or "MD" field contains the key into our database to
retrieve the transaction data, and is posted back to the TermUrl after the
customer inputs his password.
Payer Authentication Response
At this point, the merchant has sent the customer on to the credit card brand's ACS for authentication. When the
customer comes back, they will be sent back to us from the ACS to the TermURL. As you can see from the previous sample code, on line
3 the TermURL was sent as Request.Url.Authority + "/3dsResponse.aspx". Inside
3dsResponse.aspx, we'll get the two form variables that were posted back to us by the ACS, "MD" and "PARes". "MD" is the value that we passed in
with the authentication request, and we'll use it to look up the details of the transaction in progress. Using this transaction key
we'll look up the transaction id, amount, cardnumber, and any other previously stored information that we need to continue. "PARes" is the payer
authentication response which we will pass to the CheckAuthenticationResponse method after setting the appropriate transaction properties,
like so:
13DS.RootCertificate = "MIIBwDCCASmgAwIB...";
13DS.RootCertificate = "+MIICHjCCAYegAwIB...";
23DS.MerchantBankId = "999999";
33DS.MerchantNumber = "TEST_NUMBER";
43DS.TransactionId = transaction_id;
53DS.TransactionAmount = transaction_amount;
63DS.CardNumber = transaction_cardnumber;
73DS.MessageId = transaction_messageid;
83DS.CheckAuthenticationResponse(Request.Form["PARes"]);
Note the RootCertificate property settings on lines 1 and 2 in the sample code above. Visa, MasterCard, and/or JCB will have provided you with one
or more public keys that you can use to verify their signature. These public keys should be passed to the component through this
RootCertificate property. Prepend a "+" character to the base64 encoded certificate body to append to the RootCertificate list instead of
overwriting. The CheckAuthenticationResponse method will verify that the response really came from the ACS (through signature verification).
If no errors are thrown by CheckAuthenticationResponse, then the signature was verified and you can trust that the response is valid.
If the authentication was successful, AuthenticationStatus will contain "Y". If authentication fails, the AuthenticationStatus will
contain "N". If the authentication is successful, you must pass the TransactionId, AuthenticationCAVV, and AuthenticationECI properties
in the credit card authorization request (handled by other software, such as one of the
/n software Integrator products that are for credit card payments) in order to qualify for the extra protection and discount. If the
AuthenticationStatus is "N" you MUST NOT complete the transaction.
Note: Even if the AuthenticationStatus contains "Y", the transaction should not be considered authenticated if the signature verification
fails. A transaction may only be considered authenticated if no errors are generated by the CheckAuthenticationResponse method and the
value of AuthenticationStatus is "Y".
Authorization
Finally, the 3-D secure authentication is completed, CheckAuthenticationResponse succeeded and AuthenticationStatus was "Y", so we can
charge the customers credit card. Here are a few examples of how this can be done:
- TSYS Integrator
1directcharge1.CardNumber = transaction_cardnumber;
2directcharge1.CardExpMonth = transaction_cardexpmonth;
3directcharge1.CardExpYear = transaction_cardexpyear;
4directcharge1.CustomerAddress transaction_customeraddress;
5directcharge1.CustomerZip = transaction_customerzip;
6directcharge1.TransactionAmount = transaction_amount;
7directcharge1.TransactionNumber = "0001" 'increment for each transaction
8directcharge1.XID = 3DS.TransactionId;
9directcharge1.ECI = 3DS.AuthenticationECI;
10directcharge1.CAVV = 3DS.AuthenticationCAVV;
- E-Payment Integrator
How to support 3-D Secure in the E-Payment Integrator depends on which gateway you're using, because each gateway might expect the transactionId,
authenticationECI, and authenticationCAVV to be called different things. Once you know what the gateway you're using calls these fields,
you can simply use the AddSpecialFields method of the ICharge component to add these fields to the outgoing request. Prior to calling the Authorize
method, simply add each special field. For example:
USAEPay:
1icharge1.AddSpecialField("UMxid", 3DS.TransactionId);
2icharge1.AddSpecialField("UMeci", 3DS.AuthenticationECI);
3icharge1.AddSpecialField("UMcavv", 3DS.AuthenticationCAVV);
Paymentech Orbital:
1icharge1.AddSpecialField("XID", 3DS.TransactionId);
2icharge1.AddSpecialField("AuthenticationECIInd", 3DS.AuthenticationECI);
3icharge1.AddSpecialField("CAVV", 3DS.AuthenticationCAVV);
4// If this is a MasterCard instead of a Visa,
// use AAV instead of CAVV.
Authorize.Net:
1icharge1.AddSpecialField("x_authentication_indicator",
2 3DS.AuthenticationECI);
3icharge1.AddSpecialField("x_cardholder_authentication_value",
4 3DS.AuthenticationCAVV);
Testing
The "dummy" test servers used in this tutorial and in the accompanying demo applications are not real and should not be used
with real customer data. These servers are not complete servers, but basic stubs designed to allow simple code testing, and they will only respond
with hard-coded transaction information, and will only work with the supplied example values. Feel free to use these servers during your development.
After you are confident in your solution, you'll need to undergo some amount of testing with Visa, MasterCard, and/or JCB (depending on which of their
programs you would like to support). If you are going to support Verified By Visa, you'll have to complete Visa's PIT testing process. As stated earlier
in this tutorial, the /nsoftware 3-D Secure MPI is certified and has gone through interoperability testing with Visa. Even so, every merchant that signs up
for Verified By Visa is required to complete PIT testing. You can use our PIT Testing
overview for a step-by-step explanation of how to complete PIT testing.
MasterCard SecureCode and
JCB J/Secure also have test infrastructures for your
convenience.
For debugging, the component provides a ResponsePacket property, a DataPacketIn event, and a DataPacketOut event. The ResponsePacket
property can be used to access the responses received from the directory server after a call to RequestCardRanges or VerifyEnrollment.
It can also be used to access the PARes received from the ACS after calling CheckAuthenticationResponse. The two events, DataPacketOut and
DataPacketIn, are fired when sending/receiving data packets to/from a remote server. You can also use the DataPacketOut event to view
the unencrypted XML version of the PAReq after a call to GetAuthenticationPacket. Note that in the classic asp edition, where there are no events,
the DataPacketOut and ResponsePacket properties can be used to read the last data sent to and received from the directory server and/or access control server.
Conclusion
This article showed how to add 3-D Secure authentication to any merchant payment system. The /nsoftware E-Payment Integrator can be used to
plug-in to an existing system, or it can be combined with one of the
/n software Integrator products to create a complete solution from scratch.
Here we talked about the basics that you
need to get started, but we recommend that you also take a look at the documentation of the /nsoftware E-Payment Integrator that comes installed with the product, as it
goes into details about all available properties of the component, including many that were not discussed here.
Please note that in a real production environment you will want to log all
messages from both the E-Payment Integrator and TSYS components. You will also
want to use your own database code to load and store partially completed
transactions.
Read more information about the products mentioned above: /n software E-Payment Integrator,
& /n software TSYS Integrator.