Cardholder authentication service

The purpose of this Web Service is to authenticate the holder of the payment card using 3DS v1 or 3DS v2 protocols (other authentication protocols can be potentially added to this list). The service offers automatic selection of protocol, with transparent fallback to 3DS v1 if 3DS v2 is not possible.

The service authenticates the cardholder and returns the authentication information at the end of the process.

General principle

The service adopts an operating principle that ignores the underlying protocol to provide a unique integration experience, and not integration by protocol.

The generic process of complete authentication consists of several stages:

  • an initial call to the Charge/Authenticate service with a response of RESULT or INSTRUCTION type.
  • if the return belongs to the typeINSTRUCTION, the operation must be performed on the merchant side:
    • creation of a visible or invisible iFrame
    • in the iFrame, browser redirect to a target page after submitting a form that respects the definition specified in the instruction
    • potential interaction with the cardholder or the browser
    • return page of the remote server that will emit a JavaScript event containing the result of the instruction
    • interception of the instruction result in the form of a JavaScript event in the parent window
    • new call to the Charge/Authenticate service with the signed result of the instruction obtained via the browser
    • the Charge/Authenticate service returns either an instruction or a result
  • if the return is of RESULT type, it will contain the final authentication result and the process ends.

Detailed flowchart

The following flowchart presents a generic payment scenario with authentication: the initial call to the service, an instruction, an interaction, the final authentication result and the end of payment.

We will present the different steps of the integration in the following paragraphs.

Integration Stages
Actions to perform on the merchant server side steps 3, 4, 16 et 17
Actions to perform on the JavaScript side steps 5, 6, 7 et 15

Steps 1 and 2: Initiation (payment or addition of the card)

An action of payment or card registration has been initiated and requires authentication. The Charge/Authenticate service is ready to be called.

Step 3: Call to the Charge/Authenticate service

The initial request allows to transmit the data required for authentication. Here is an example of a request:

{
  "device": {
    "type": "BROWSER",
    "acceptHeader": "application/json",
    "ip": "89.249.65.28", 
    "javaEnabled": true,
    "language": "en",
    "colorDepth": "1",
    "screenHeight": 1024,
    "screenWidth": 768,
    "timezoneOffset": 0,
    "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
  },
  "productType": "GOODS_OR_SERVICE_PURCHASE",
  "merchant": {
    "mid": "123456"
  },
  "transactionCategory": "PAYMENT",
  "amount": 1230,
  "currency": "EUR",
  "paymentForm":{
    "pan": "4970100000000014",
    "expiryMonth": "02",
    "expiryYear": "22",
	  "accountType": "DEBIT"
  }
}
/**
 * I initialize the PHP SDK
 */
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/keys.php';
require_once __DIR__ . '/helpers.php';

/** 
 * Initialize the SDK 
 * see keys.php
 */
$client = new Lyra\Client();

/**
 * I create a formToken
 */
$store = array("amount" => 250, 
"currency" => "EUR", 
"orderId" => uniqid("MyOrderId"),
"customer" => array(
  "email" => "sample@example.com"
));
$response = $client->post("V4/Charge/CreatePayment", $store);

/* I check if there are some errors */
if ($response['status'] != 'SUCCESS') {
    /* an error occurs, I throw an exception */
    display_error($response);
    $error = $response['answer'];
    throw new Exception("error " . $error['errorCode'] . ": " . $error['errorMessage'] );
}

/* everything is fine, I extract the formToken */
$formToken = $response["answer"]["formToken"];

?>

Step 4: Full response with an instruction

The response will contain an instruction presented as follows (this example presents 3DS v1 authentication):

{
  "answer": {
	  "id": "c82794e9-9c20-44a8-9297-b70e1e7c4006",
	  "protocol": {
			"name": "THREEDS",
			"version": "1.0.2",
			"challengePreference":"NO_PREFERENCE",
			"simulation":false
		},
		
	  "value": {
  		"responseType": "INSTRUCTION",
			"instructionType": "FORM",
			"name": "CHALLENGE",
			"timeout" : "15",
			"target": {
				"element": "IFRAME",
				"visible": true,
				"width": 400,
				"height": 400
			},

			"http": {
				"method": "POST",
				"url": "https://acs.sg.com/1.0.2",
				"headers": {
					"Accept": "text/html"
				},
				"body": {
					"termUrl": "https://pass.sample-acs.net/v1/notify/threeds/v1/pares",
					"MD": "eJwljEmSokAAAL8yd2O6imLVCA+oINAKCLLekALZd2ggePz0dF/ylJnEB/xAG8GQLLcRiKRoZgtWnHtkwniZfw2qontZg4mvIv2SrOOGIMERCDJ/CHSg2QMkNpqEcNt/52iDEP1/bdVYFFsyDM0BgKIOgyKp++HAQQ6CKcD93yZYyqgawK/4A6VlbYPzWv0OZu3Gj04+rf6LMlQP8db81Tm7JXBxyrM3cKIYaV7GedZVQdLkWAo6W+ufqbUMjQxLQvkUIG8k384FpmsJfG2fQ0qzI3rulyLFqkPMYD9No8B48rkcrmI59ar3Yk29l6k8EQJPDlc9p+OqPzuxhul33WZx2TvmyNBxswb2U9OmCHFhelH8WI6e3nV2xVACYrHwadbjVpKbxxjWjywfgi7EK3ZWGTMnsSl2baxnlWKWhmXuqpOXX2JBhDDUebZccWyNOagnJHKm+kgz//4OF8oyrWig5hIAw1LL7jNTTkiw76DgJDl2VXKxGc4h0O1W9e4k1b4LPeRfzsh6H4//ANdloIQ=",
					"paReq": "eJxVUslu2zAQ/RVBd5mLLZk2RgzSBlkOCYLGPqSXgss4VmNJDkkHdr4+pKosPXHezPDN4xvC2bHdZa/ofNN3dc4mNM+wM71tuqc6X68uC5FnPqjOql3fYZ2f0OdnElZbh3jxgObgUMIteq+eMGtsnf8RSghqDS0st7yY0WpeaKNZoamwrFpQzSvMJdyf/8IXCeNoGSdPOJAPGCmd2aouSFDm5cfNnWTVdC6AjAhadDcXkvHprKyA/EPQqRblrRpu2hX6AGRIgekPXXAnyUsK5APAwe3kNoS9XxLSjrcmpm+BpAqQLw33hxT5yHRsrFRv9vlxuq0e//6+Ut3O6XV4sFeXpb5e10BSB1gVUHLKBOO0yhhflvMlZUCGPKg2SZDllEY5I4B9mnH+vfI9A9FpFzdzkotkwycCPO7jYmJHdO8zBovexBeMx5f8n9fJUBOSdxsurFa0VJrPNqg0ZTjb2LnhJU8+D02JvoleMUEXA38CQBINGTdIxu3H6L9f8Q7HNMYj"
				}
			}
	  }
  }
}

It consists of:

Object Function
id Identifiant unique de la transaction d’authentification en cours.Il devra être retransmis à chaque nouvel appel.
protocol Indicates which protocol will be eventually applied during the authentication.
value Represents the result of the authentication or instruction to follow. If the responseType attribute indicates INSTRUCTION, it is the instruction to be executed, if it indicates RESULT, it is the result of the authentication.

Step 5: Preparation of the instruction management page

If an instruction was returned in the previous step, the page displayed in this step must allow:

  • la mise en place d’un listener sur le type d’événement renvoyé par l’iFrame, qui déclenchera un POST vers le serveur marchand avec le résultat d’instruction (cf.étape 15).
  • la création d’iFrame masquée ou visible (cf.étapes 6 et 7).

Step 6: Creation of an iFrame

The instruction received in step 4 is as follows:

{
    "responseType": "INSTRUCTION",
    "instructionType": "FORM",
    "name": "CHALLENGE",
    "timeout" : "15",
    "target": {
        "element": "IFRAME",
        "visible": true,
        "width": 400,
        "height": 400
    },

    "http": {
        "method": "POST",
        "url": "https://acs.sg.com/1.0.2",
        "headers": {
            "Accept": "text/html"
        },
        "body": {
            "termUrl": "https://pass.sample-acs.net/v1/notify/threeds/v1/pares",
            "MD": "eJwljEmSokAAAL8yd2O6imLVCA+oINAKCLLekALZd2ggePz0dF/ylJnEB/xAG8GQLLcRiKRoZgtWnHtkwniZfw2qontZg4mvIv2SrOOGIMERCDJ/CHSg2QMkNpqEcNt/52iDEP1/bdVYFFsyDM0BgKIOgyKp++HAQQ6CKcD93yZYyqgawK/4A6VlbYPzWv0OZu3Gj04+rf6LMlQP8db81Tm7JXBxyrM3cKIYaV7GedZVQdLkWAo6W+ufqbUMjQxLQvkUIG8k384FpmsJfG2fQ0qzI3rulyLFqkPMYD9No8B48rkcrmI59ar3Yk29l6k8EQJPDlc9p+OqPzuxhul33WZx2TvmyNBxswb2U9OmCHFhelH8WI6e3nV2xVACYrHwadbjVpKbxxjWjywfgi7EK3ZWGTMnsSl2baxnlWKWhmXuqpOXX2JBhDDUebZccWyNOagnJHKm+kgz//4OF8oyrWig5hIAw1LL7jNTTkiw76DgJDl2VXKxGc4h0O1W9e4k1b4LPeRfzsh6H4//ANdloIQ=",
            "paReq": "eJxVUslu2zAQ/RVBd5mLLZk2RgzSBlkOCYLGPqSXgss4VmNJDkkHdr4+pKosPXHezPDN4xvC2bHdZa/ofNN3dc4mNM+wM71tuqc6X68uC5FnPqjOql3fYZ2f0OdnElZbh3jxgObgUMIteq+eMGtsnf8RSghqDS0st7yY0WpeaKNZoamwrFpQzSvMJdyf/8IXCeNoGSdPOJAPGCmd2aouSFDm5cfNnWTVdC6AjAhadDcXkvHprKyA/EPQqRblrRpu2hX6AGRIgekPXXAnyUsK5APAwe3kNoS9XxLSjrcmpm+BpAqQLw33hxT5yHRsrFRv9vlxuq0e//6+Ut3O6XV4sFeXpb5e10BSB1gVUHLKBOO0yhhflvMlZUCGPKg2SZDllEY5I4B9mnH+vfI9A9FpFzdzkotkwycCPO7jYmJHdO8zBovexBeMx5f8n9fJUBOSdxsurFa0VJrPNqg0ZTjb2LnhJU8+D02JvoleMUEXA38CQBINGTdIxu3H6L9f8Q7HNMYj"
        }
    }
}

The different properties of the iFrame to be created can be found in the target element:

		"target": {
		  "element": "IFRAME",
		  "visible": true,
		  "width": 400,
		  "height": 400
		}

If it must be visible (value.target.visible attribute set to true), create the iFrame with these parameters (using width and height) and display it, or create a hidden iFrame.

Example of implementation:

    function createInstructionIframe(instruction) {
        // Get instruction container element
        container = document.getElementById('instructionContainer');

        // Clean instruction container
        container.innerHTML = '';

        // Create iframe element
        var iframe = document.createElement('iframe');
        iframe.id = 'instructionIframe';
        iframe.name = 'instructionIframe';
        iframe.src = 'about:blank';
        iframe.style.width = instruction.target.width;
        iframe.style.height = instruction.target.height;
        iframe.style.visibility = instruction.target.visible ? 'visible' : 'hidden';

        // Add iframe to container
        container.appendChild(iframe);

        // Create form to post
        var form = document.createElement('form');
        form.id = 'instructionForm';
        form.name = 'instructionForm';
        form.target = 'instructionIframe';
        form.method = instruction.http.method;
        form.action = instruction.http.url;
        form.style = 'visibility: hidden';

        // Create form body
        Object.keys(instruction.http.body).forEach(function (name) {
            form.innerHTML += '';
        });
        var body = document.createElement('form');

        // Add form to container
        container.appendChild(form);

        // Triger form submit
        form.submit();
    }

Step 7: Form submission

Once the iFrame has been created, it must be filled with a form following the instructions of the ‘http’ tag:

"http": {
	"method": "POST",
	"url": "https://acs.sg.com/1.0.2",
	"headers": {
		"Accept": "text/html"
	},
	"body": {
		"termUrl": "https://pass.sample-acs.net/v1/notify/threeds/v1/pares",
		"MD": "eJwljEmSokAAAL8yd2O6imLVCA+oINAKCLLekALZd2ggePz0dF/ylJnEB/xAG8GQLLcRiKRoZgtWnHtkwniZfw2qontZg4mvIv2SrOOGIMERCDJ/CHSg2QMkNpqEcNt/52iDEP1/bdVYFFsyDM0BgKIOgyKp++HAQQ6CKcD93yZYyqgawK/4A6VlbYPzWv0OZu3Gj04+rf6LMlQP8db81Tm7JXBxyrM3cKIYaV7GedZVQdLkWAo6W+ufqbUMjQxLQvkUIG8k384FpmsJfG2fQ0qzI3rulyLFqkPMYD9No8B48rkcrmI59ar3Yk29l6k8EQJPDlc9p+OqPzuxhul33WZx2TvmyNBxswb2U9OmCHFhelH8WI6e3nV2xVACYrHwadbjVpKbxxjWjywfgi7EK3ZWGTMnsSl2baxnlWKWhmXuqpOXX2JBhDDUebZccWyNOagnJHKm+kgz//4OF8oyrWig5hIAw1LL7jNTTkiw76DgJDl2VXKxGc4h0O1W9e4k1b4LPeRfzsh6H4//ANdloIQ=",
		"paReq": "eJxVUslu2zAQ/RVBd5mLLZk2RgzSBlkOCYLGPqSXgss4VmNJDkkHdr4+pKosPXHezPDN4xvC2bHdZa/ofNN3dc4mNM+wM71tuqc6X68uC5FnPqjOql3fYZ2f0OdnElZbh3jxgObgUMIteq+eMGtsnf8RSghqDS0st7yY0WpeaKNZoamwrFpQzSvMJdyf/8IXCeNoGSdPOJAPGCmd2aouSFDm5cfNnWTVdC6AjAhadDcXkvHprKyA/EPQqRblrRpu2hX6AGRIgekPXXAnyUsK5APAwe3kNoS9XxLSjrcmpm+BpAqQLw33hxT5yHRsrFRv9vlxuq0e//6+Ut3O6XV4sFeXpb5e10BSB1gVUHLKBOO0yhhflvMlZUCGPKg2SZDllEY5I4B9mnH+vfI9A9FpFzdzkotkwycCPO7jYmJHdO8zBovexBeMx5f8n9fJUBOSdxsurFa0VJrPNqg0ZTjb2LnhJU8+D02JvoleMUEXA38CQBINGTdIxu3H6L9f8Q7HNMYj"
	}
}
  • the method property indicates the HTTP verb to be associated with the form
  • url indicates which server is targeted by the form action
  • the HTTP request headers in headers
  • the form parameters in body (e.g. termUrl, MD and paReq)

Once the form has been generated and placed in the iFrame, all you need to do is submit it on page load.

Managing timeouts

If the instruction contains the timeout attribute, you must initiate a return to the authentication server by emitting an event of LYRA_AUTH_INSTRUCTION_RESULT type populated as follows:

{
    eventName: 'LYRA_AUTH_INSTRUCTION_RESULT',
    value: {
        name: "Insérer ici le nom de l'instruction reçue en réponse",
        value: 'TIMEOUT',
        protocol: "Insérer ici l'objet protocol reçu en réponse"
    }
}

The event will be captured by the listener whose details are provided in step 15. This will allow to pursue the process and obtain a final result.

Steps 8 to 14: User authentication

Once the form has been posted, the code of the issuing bank will handle the process to allow for a secure authentication (silent or interactive). At the end of this step, the LYRA_AUTH_INSTRUCTION_RESULT event will be emitted via the iFrame in order to indicate the end of the process. Example:

{
    "eventName": "LYRA_AUTH_INSTRUCTION_RESULT",
    "value" : {
        "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
        "name": "CHALLENGE",
        "protocol": {
            "name": "THREEDS",
            "version": "2.1.0",
        }
    }
}

Step 15: Retrieval of the JavaScript event emitted in step 14

In order to interpret the LYRA_AUTH_INSTRUCTION_RESULT event, it is necessary to implement a listener on the main page. It must be capable of parsing JSON code and must be written as follows:

window.addEventListener('message', function (messageEvent) {
    
        var data = messageEvent.data;
        try {
            var messageData = JSON.parse(data);
            if (messageData.eventName === 'LYRA_AUTH_INSTRUCTION_RESULT') {
                try {
                    // callback call with messageData.value content
                } catch (err) {
                    // error callback call
                } finally {
                    // always close the iFrame/popin
                }
            }
        } catch (err) {
            // process eventual exceptions during callbacks
        }
    
}, false);

After that, you must return this data to the merchant server.

Step 16: Return of the instruction result to the merchant server

Once the instruction result has been retrieved on the merchant server side, it must be returned via a new call to the Charge/Authenticate service. The instructionResult object will have to be added to the initial request:

{
  "id": "c82794e9-9c20-44a8-9297-b70e1e7c4006",
  "device": {
    "type": "BROWSER",
    "acceptHeader": "application/json",
    "ip": "89.249.65.28", 
    "javaEnabled": true,
    "language": "en",
    "colorDepth": "1",
    "screenHeight": 1024,
    "screenWidth": 768,
    "timezoneOffset": 0,
    "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
  },
  "productType": "GOODS_OR_SERVICE_PURCHASE",
  "merchant": {
    "mid": "123456"
  },	
  "transactionCategory": "PAYMENT",
  "amount": 1230,
  "currency": "EUR",
  "paymentForm":{
    "pan": "4970100000000014",
    "expiryMonth": "02",
    "expiryYear": "22",
	  "accountType": "DEBIT"
  },
  "instructionResult": {
    "name" : "CHALLENGE",
    "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
    "protocol" : {
      "name" : "THREEDS",
      "version" : "1.0.2",
      "challengePreference": "NO_PREFERENCE",
      "simulation": false
    }
  }
}
/**
 * I initialize the PHP SDK
 */
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/keys.php';
require_once __DIR__ . '/helpers.php';

/** 
 * Initialize the SDK 
 * see keys.php
 */
$client = new Lyra\Client();

/**
 * I create a formToken
 */
$store = array("amount" => 250, 
"currency" => "EUR", 
"orderId" => uniqid("MyOrderId"),
"customer" => array(
  "email" => "sample@example.com"
));
$response = $client->post("V4/Charge/CreatePayment", $store);

/* I check if there are some errors */
if ($response['status'] != 'SUCCESS') {
    /* an error occurs, I throw an exception */
    display_error($response);
    $error = $response['answer'];
    throw new Exception("error " . $error['errorCode'] . ": " . $error['errorMessage'] );
}

/* everything is fine, I extract the formToken */
$formToken = $response["answer"]["formToken"];

?>

Step 17: Receiving the response from the payment gateway server

Similarly to step 4, the merchant server receives a new response that can either be final (RESULT) or request a new instruction (INSTRUCTION). In the second case, the flow resumes at step 5. Here is an example of a final message:

{
    "answer": {
        "id": "c82794e9-9c20-44a8-9297-b70e1e7c4006",
  
        "protocol": {
          "name": "THREEDS",
          "version": "1.0.2",
          "challengePreference":"NO_PREFERENCE",
          "simulation":false
        },
  
        "value": {
          "responseType": "RESULT",
          "authenticationId":{
            "authenticationIdType":"xid",
            "value":"c82794e99c2044a89297b70e1e7c4006"
          },
          "status": "SUCCESS",
          "authenticationType": "CHALLENGE",
          "authenticationValue":{
              "authenticationValueType": "CAVV",
              "value": "FsXD4Ox0VEI2MseoR0VhN5pX952I"
          },
          "commerceIndicator": "05",
          "extension": {
            "enrolled": "Y",
            "algorithm": "2",
            "signatureValid": true
          }
        }
      }
  }

Step 18: The merchant server resumes operations

If the previous response is a final result, the merchant server must analyze the status of the result (‘value.status’ property) in order to resume the operation in progress (e.g. authorization if ‘SUCCESS’ of end of payment or card registration if ‘FAILED’…).

Appendix

Example: 3DS v1 authentication with ACS authentication

  • an initial call to the Charge/Authenticate service with a card enrolled to 3DS v1
  • a return with a CHALLENGE instruction of redirection to the ACS with a paReq (visible iFrame)
  • a redirection to the ACS in the iFrame, authentication of the holder
  • a return via the browser with an instruction result
  • a new call to the Charge/Authenticate service by transmitting this result
  • a return of the payment gateway server with the final authentication result

Example: 3DS v2 authentication with ACS authentication

  • an initial call to the Charge/Authenticate service with a card enrolled to 3DS v2
  • a return with a FINGERPRINT instruction (3DS Method)
  • a redirection to the ACS in the invisible iFrame, loading and execution of the JavaScript code of the ACS fingerprint
  • a return via the browser with an instruction result
  • a new call to the Charge/Authenticate service by transmitting this result
  • a return of the payment gateway server with a CHALLENGE instruction of redirection to the ACS with a CReq (visible iFrame)
  • the instruction has occurred (redirection to the ACS with a CReq and user interaction)
  • the browser return is an instruction result: new call to the Charge/Authenticate service by transmitting this result
  • the server return is the final result of the authentication

Glossary

3DS Method JavaScript code of the ACS executed in the buyer’s browser for the purpose of making fingerprints.
3DS Requestor The requestor upon 3DS authentication, usually the merchant or their payment gateway.
3DS Server 3DS Server. Component of the 3DS Requestor domain that initiates the 3DS v2 process and communicates with the DS or the ACS during transaction authentications. It facilitates the interaction between the 3DS Requestor and the DS.
ACS Access Control Server. Component that checks whether authentication is available for a card number and authenticates specific transactions.
3DS Requestor application Application on the buyer’s mobile device that can process a 3DS transaction thanks to the use of 3DS SDK. The application is available by means of integration with 3DS SDK.
Challenge Interactive authentication phase between the buyer and their bank (ACS).
CReq 3DS v2 request message of cardholder authentication, sent to the ACS.
DS Directory Server. Component that maintains the list of intervals for cards with possible authentication allowing MPIs / 3DS Servers / ACS to communicate with each other during authentications.
Fingerprinting Corresponds to getting a fingerprint. Unique identification of the buyer using browser data.
MPI Merchant Plug-In. Component that initiates the 3DS v1 process and communicates with the DS or the ACS during transaction authentications.
paReq 3DS v1 request message of cardholder authentication, sent to the ACS.
3DS SDK 3D Secure development kit. Software component included in a 3DS Requestor Application

List of supported protocols

Protocol Version
3D Secure 1.0.2
3D Secure 2.1.0

Test cards

The test card reference page can be found here.