5

The documentation for Protocol 4.00 could be more helpful. For everyone struggling to get 3DSV2 working, I'd like the basics spelled out by anyone who has managed to get it working.

I'll summarise the flow as I understand it, please everyone, help by correcting where necessary and by adding in any issues such as removing the {} braces from VPSTx_Id.

  1. Make your request to SagePay to register the transaction, include ThreeDSNotificationURL which is the url where the ACS will redirect your customer if successful, or not.
  2. If the response from SagePay is 3DAUTH, build a form to show to the customer that contains an iFrame with the required fields "acsUrl" "creq" and "threeDSSessionData", fields filled in from the SagePay response. (Page 16 in the Protocal 4 guidelines). Note *

    The documentation says to make this an auto-submit form, but it may be better to inform the customer why they are authenticating to their bank and get them to click a button to proceed. YMMV

  3. Customer fills in the authentication form in the iFrame.
  4. Card issuing bank sends back successful or not response to your ThreeDSNotificationURL
  5. threeDSSessionData or (MD) and CRes or (PARes) are sent back in this response depending on 3DSv2 or (3DSv1) responded.
  6. Your ThreeDSNotificationURL code must then post to the SagePay callback page VPSTxId and Cres or MD and PARes again depending on 3DSv2 or 3DSv1
  7. SagePay will request card authorisation if 3DS authentication was successful.
  8. SagePay then responds with VPSTxId and 10 digit SecurityKey if authorisation was approved.
  9. Display completion page and inform customer of successful or not successful transaction.
  10. Some clarification needed, 'In a fallback scenario, The Sage Pay MPI will perform a 3DSv1 enrolment request,' what is the best way to determine from the response that 3DSV1 is being used, i.e. the iFrame form must contain PaReq, MD and TermUrl instead of creq and threeDSSessionData as per point 2.) above.

When testing put CHALLENGE in the card holder field to test the 3D aspects.

Are there any issues to be aware of when setting up your account for 3DSv2 on MySagePay?

Sorry for the long post but I'm sure there are a lot of people trying to make this work before the deadline.

Smitthhy
  • 51
  • 1
  • 4
  • When the Bank has finished authenticating the customer, it calls back my system on the call back url, however there is a delay between the challenge window (iFrame) clearing and my script being executed on call back. This is potentially confusing for the customer, is there a way to display a message that processing is continuing and the customer should just wait a few moments? – Smitthhy Sep 04 '19 at 13:36
  • it depends on how you're processing the 3DS response, the way I've implemented it is a method which accepts the cres POST, sets up the cres for processing and returns a view. The view has some processing graphics and a call to another method which checks the cres then redirects based on pass/fail. – 0xFF Sep 12 '19 at 10:04

4 Answers4

2

Well written Smitthhy. I do agree that the documentation could be more straight forward. Did my head in the past weeks. To your 1) you need to post all required fields mentioned in the documentation. To 8) you get more data back from SagePay. Looks like below:

VPSProtocol=4.00
Status=OK
StatusDetail=0000 : The Authorisation was Successful.
VPSTxId={1B19CB3F-E553-0E69-CFD5-6D75B53753C1}
SecurityKey=UAW4ZETUK7
TxAuthNo=2261559
AVSCV2=SECURITY CODE MATCH ONLY
AddressResult=NOTMATCHED
PostCodeResult=NOTMATCHED
CV2Result=MATCHED
3DSecureStatus=OK
CAVV=Q042ZUZRWndDbjAyWHRjYUFkZ2c=
DeclineCode=00
ExpiryDate=1035
BankAuthCode=999778

To 9) You can differentiate between 3DSecure v1 and 3DSecure v2 by checking the StatusDetails you get from SagePay.

3DSv1 returns StatusDetail=2007
3DSv2 returns StatusDetail=2021

I do the Payment Processing in a class file which is called by my Checkout page. The class returns the response to the Checkout page with the details I need. They are different for v1 and v2.

For v1 I return:
return "v1" + Status + "&3DSecureStatus=" + s3DSecureStatus + "&MD=" + sMD + "&ACSURL=" + sACSURL + "&PAReq=" + sPAReq + "&VendorTxCode=" + o.OrderID;

For v2 I return:
return "v2" + Status + "&3DSecureStatus=" + s3DSecureStatus + "&VPSTxId=" + sVPSTxId + "&ACSURL=" + sACSURL + "&CReq=" + sCReq + "&VendorTxCode=" + o.OrderID;

This allows me to act accordingly in the Checkout code.

I redirect v1 to a page with the iFrame. The iFrame loads the ACSURL received in the reponse earlier. This shows straight away the "challenge" window.

This is mainly down to the fact that SagePay accepts a URL with a query string for 3DSv1 and expects a form post for 3DSv2.

v2 redirects to another page with an iFrame. The iFrame loads a page on my website first:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ChallengeiFrame.aspx.cs" Inherits="ac_ChallengeiFrame" %>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
     <title></title>
</head>
<body>
 <div id="content">
 <div id="contentHeader">
    Your Bank requires Authentication
 </div>
 <p>
     Please click the button below to continue.
 </p>

 <form action="<%= sACSUrl %>" method="post">
     <input type="hidden" name="creq" value="<%= sCReq %>" />
     <input type="hidden" name="threeDSSessionData" value="<%= sVPSTxId %>" />
     <input type="submit" value="Click to continue" />
 </form>
 </div>
 </body>
 </html>

Clicking the button posts to the ACSURL and the challenge window shows. The customer fills in the password and submits. The bank responds to the page you assigned for v1 it's the TermUrl and for v2 it's the ThreeDSNotificationURL.

On those pages you post what you need to post and handle the response from SagePay. If all goes well the payment has been received and you can redirect your customer to the Thank you page and finish the order.

Basically, I use 2 sets of code files to handle 3DSv1 and 3DSv2. Like to keep it seperated and once 3DSv1 gets discontinued I simply can delete those files and remove the code blocks in my payment processing page and checkout page. Shouldbe straight forward then.

Hope this helps.

Here the link to the 3DSecure v2 documentation: DIRECT_Integration_and_Protocol_4_Guidelines.pdf

EDIT

ThreeDSNotificationURL code for the WebRequest and HttpWebResponse:

   /////////////////////////////////////////////////////////
   //// This is to get the posted results from the bank
   /////////////////////////////////////////////////////////
   NameValueCollection coll;
   coll = Request.Form;
   /////////////////////////////////////////////////////////
   string sSagePayUrl = "";
   if (EcommerceSettings.bLiveTransactions()) //That's just some logic so I can control live or test at one place in a settings class file.
   {
        sSagePayUrl = "https://live.sagepay.com/gateway/service/direct3dcallback.vsp?";
   }
   else
   {
        sSagePayUrl = "https://test.sagepay.com/gateway/service/direct3dcallback.vsp?";
   }
   ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
   WebRequest request = WebRequest.Create(sSagePayUrl + "cres=" + coll["cres"] + "&VPSTxId=" + coll["threeDSSessionData"]);
   // Get the response.
   HttpWebResponse getResponse = (HttpWebResponse)request.GetResponse();
   // Display the status.
   // Get the stream containing content returned by the server.
   Stream dataStream = getResponse.GetResponseStream();
   // Open the stream using a StreamReader for easy access.
   StreamReader reader = new StreamReader(dataStream);
   // Read the content.
   string responseFromServer = reader.ReadToEnd();
   // Cleanup the streams and the response.
   reader.Close();
   dataStream.Close();
   getResponse.Close();
   //Check the response and act accordingly

You need to build the request differently for 3DSv1: Here my way in the TermUrl page:

vendorTxCode = Request.QueryString["VendorTx"];
NameValueCollection coll;
coll = Request.Form;
sMd = coll["MD"];
sPaRes = coll["PaRes"];

////////////////////////////////////////////////////
//// Build post to SagePay
////////////////////////////////////////////////////
StringBuilder sb = new StringBuilder();
if (EcommerceSettings.bLiveTransactions())
{
    sb.Append("https://live.sagepay.com/gateway/service/direct3dcallback.vsp?");
}
else
{
    sb.Append("https://test.sagepay.com/gateway/service/direct3dcallback.vsp?");
}
sb.Append("VendorTxCode=");
sb.Append(sOrderID);
sb.Append("&MD=");
sb.Append(sMD);
sb.Append("&PaRes=");
sPaRes = sPaRes.Replace(" ", "+");//HttpUtility.UrlEncode(sPaRes);
sb.Append(sPaRes);
string sRequestQuery = sb.ToString();

/////////////////////////////////////////////////////
//// Post To SagePay 3DCallback page
/////////////////////////////////////////////////////
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
WebRequest request = WebRequest.Create(sRequestQuery);

Handle the response as shown for v2.

EDIT

I found that you best do a post for 3DSv1 and not using the URL parameters as some banks do not accept this. Pretty much the same way as for 3DSv2

This never came up on the test server and happened only when live.

It looks like the test server is not providing the various possibilities we encounter once we are live.

KH S
  • 444
  • 1
  • 4
  • 8
  • Thanks I agree better to keep code for v1 and v2 separate. I'm still unclear on is the mechanism of "Step 6: 3D-Authenticaiton and your site called back" (Protocol 4 Guidelines). Once complete (either successfully or not), the ACS will redirect your customer back to the URL you supplied in the ThreeDSNotificationURL, which you provided in Step 2 (or the TermURL). How can ACS redirect my customer back to the ThreeDSNotificationURL? Do they open the ThreeDSNotificationURL/TermURL in the same window that I have opened a page with the iFrame for them to authenticate to their bank? – Smitthhy Sep 02 '19 at 20:08
  • Smitthhy, once the challenge (either protocol) has been completed (data posted to the bank) the bank posts back the result. For 3DS v2 the answer goes to the ThreeDSNotificationURL (aspx page in my solutions) there I do a WebRequest to SagePay (I'll edit my answer and add some code). Those pages handle the response from the WebRequest and if successful payement received sends to the Thank you page and finish everything off. – KH S Sep 02 '19 at 23:08
  • Use the Magic Values in the Cardholders Name - see page 28 of the documentation. Challenge will give a a 3DS v2 challenge window. STATUS201DS simulates a fallback to 3DSv1. NOTHAUTH works. Found that the other values always return OK. Spoke with SagePay support last week and they are working on it. – KH S Sep 03 '19 at 11:00
0

Check that the PaRes you send to SagePay has no spaces. I found that some PaRes I got back had spaces. I replace spaces (" ") with a + sign like this:

PaRes = PaRes.Replace(" ", "+")

Then I use the altered value in the URL.

You are talking about 3DSecure version 1, right? 3DSecure version 2 looks for cres (cres in small letters).

Hope this helps.

KH S
  • 444
  • 1
  • 4
  • 8
0

I think it's v1 as that is in the URLs. This is all new to me. I've seen no mention of V2 anywhere yet ?

There isn't any spaces in the PaRes returned anyway.

exxos
  • 1
  • 1
0

WRT "the deadline" mentioned, my understanding of the timeline is as follows:

  1. On 14th September 2019, all ecommerce transactions need to go through some form of 3-D Secure. So integrating Direct API v3.00 or v4.00 with 3-D Secure would be fine (consumers will get a better experience with v4.00). SagePay also switch on their v4.00 API around this time, which I sort of anticipate might have teething problems.
  2. Some point in 2020: All transactions should go through 3-D Secure V2 (i.e Direct API v4.00), as card schemes (i.e Visa / MasterCard) will stop supporting 3-D Secure V1. So all merchants that have a Direct integration with SagePay for ecommerce payments will have to upgrade to v4.00

Smitthhy - To test the flow on the SagePay test system where the user has to do something, you have to send through a CardHolder of CHALLENGE (I can't reply to the other post because I don't have a SO reputation of 50 yet - sigh).

S.Thomson
  • 240
  • 1
  • 9
  • Recent email from Sagepay (25 Nov 2020) sets dates for 3Dv2: `which will be enforced from the 31 December 2020 in Europe and the 14 September 2021 in the UK respectively` – GlennG Dec 09 '20 at 10:32