HomePaymentsNo-codeDevelopersContribute
Safepay Home PageLive DashboardTest Dashboard

Payer Authentication with Cardinal guide

Accept payments using the Cardinal flow.


4

Payer Authentication Setup

After creating the payment session and the client side token, the next step is to pass in the customer payment details to the Order API.

Important: If you pass in raw card details from your server, Safepay will require you to submit a PCI DSS Attestation of Compliance (AOC). If you don’t have a PCI DSS AOC, you must submit your customer’s card information directly from your website to our APIs. We strongly recommend you sending the customer’s card information through your client website.

Initiate Payer Authentication in NodeJS
const safepay = require("@sfpy/node-core")({
  api_key: "CLIENT_SIDE_AUTH_TOKEN",
  authType: "jwt",
  host: "https://sandbox.api.getsafepay.com", // for live payments use https://api.getsafepay.com
});

(async () => {
  try {
    const response = await safepay.client.passport.token({
      payload: {
        is_mobile: true,
        payment_method: {
          card: {
            card_number: "5200000000001096",
            expiration_month: "12",
            expiration_year: "2028",
            cvv: "123",
          },
        },
      },
    });
    console.log(response);
  } catch (err) {
    console.error(err);
  }
})();

Note: You must pass "is_mobile": true for mobile-based flows. This is requirement to generate the ServerJWT.

The response from this step includes the card details and a payer_authentication_setup object containing the access_token and CardinalJwt. These are used for collecting device data and completing the enrollment step with the card issuer.

Response
{
  "action": {
    "token": "req_29ffd60c-0527-4173-920b-968175deac28",
    "payer_authentication_setup": {
      "cardinal_jwt": "eyJhbGciOiJIUzI1NiIsInR5..."
    }
  }
}

5

Initialize Cardinal SDK

Cardinal Mobile SDK Guide provides a component to manage device data collection and challenge flow for your customers.

Download the CardinalMobile.framework/CardinalMobile.xcframework file using the following cURL:

Terminal
# Install the Cardinal SDKcurl -L -u <USER_NAME>:<API_KEY> https://cardinalcommerceprod.jfrog.io/artifactory/ios/<VERSION>-<BUILD_NUMBER>/cardinalmobilesdk.zip -o <LOCAL_FILE_NAME.EXT># Example:curl -L -u UserName:ApiKey "https://cardinalcommerceprod.jfrog.io/artifactory/ios/2.2.5-6/cardinalmobilesdk.zip" -o cardinalmobilesdk.zip

Configure Cardinal Mobile SDK

Create a new instance of the Cardinal object by [CardinalService new]. SDK offers multiple configuration options for you (if not specified, everything is set to default). For more details: CardinalConfigurationOptions. Use the code snippet below for completing the configuration.

Example
#import <CardinalMobile/CardinalMobile.h>
CardinalSession *session;
//Setup can be called in viewDidLoad
- (void)setupCardinalSession {
	session = [CardinalSession new];
	CardinalSessionConfiguration *config = [CardinalSessionConfiguration new];
	config.deploymentEnvironment = CardinalSessionEnvironmentProduction;
	config.requestTimeout = CardinalSessionTimeoutStandard;
	config.challengeTimeout = 5;
	config.uiType = CardinalSessionUITypeBoth;
	UiCustomization *yourCustomUi = [[UiCustomization alloc] init];
	//Set various customizations here. See "iOS UI Customization" documentation for detail.
	config.uiCustomization = yourCustomUi;
	UiCustomization *yourDarkModeCustomUi = [[UiCustomization alloc] init];
	config.darkModeUiCustomization = yourDarkModeCustomUi;
	CardinalSessionRenderTypeArray *renderType = [[CardinalSessionRenderTypeArray alloc] initWithObjects:
    	                       	CardinalSessionRenderTypeOTP,
        	                   	CardinalSessionRenderTypeHTML,
								CardinalSessionRenderTypeOOB,
								CardinalSessionRenderTypeSingleSelect,
								CardinalSessionRenderTypeMultiSelect,
            	               nil];
	config.renderType = renderType;
	[session configure:config];
}

Available Configurations for iOS

This table outlines configuration options available in the Cardinal SDK:

Available Configuration Options for Cardinal SDK (iOS)

MethodDescriptionDefault Value(s)Possible Value(s)
deploymentEnvironmentThe environment SDK connects to.CardinalSessionEnvironmentProductionCardinalSessionEnvironmentProduction, CardinalSessionEnvironmentStaging
uiTypeInterface types the device supports for displaying challenge UIs. Interacts with renderType.
It is recommended to use CardinalSessionUITypeBoth to support both Native and HTML types. Deviating may impact performance.
CardinalSessionUITypeBothCardinalSessionUITypeBoth, CardinalSessionUITypeNative, CardinalSessionUITypeHTML
renderTypeList of render types supported by the device.
Note:
• If uiType is CardinalSessionUITypeBOTH or CardinalSessionUITypeHTML, include all render types.
• If uiType is CardinalSessionUITypeNative, exclude CardinalSessionRenderTypeHTML.
All listed typesCardinalSessionRenderTypeOTP, CardinalSessionRenderTypeHTML, CardinalSessionRenderTypeOOB, CardinalSessionRenderTypeSingleSelect, CardinalSessionRenderTypeMultiSelect
proxyServerURLProxy server through which the Cardinal SDK session operates.nullString value
requestTimeoutMaximum amount of time (in milliseconds) for all exchanges.8000Integer (≥ 0 ms)
challengeTimeoutTimeout for the challenge screen (in minutes).5Integer (≥ 5 minutes)
uiCustomizationSets custom UI customization for SDK-controlled challenge UI.Custom object
enableDFSyncEnable Device Fingerprint sync to call onSetupCompleted after data collection.truetrue, false
threeDSRequestorAppURLMerchant app URL to be used within the CReq message. Allows return to the merchant app after OOB flow.String value
collectLogsEnables collection of SDK logs.truetrue, false
darkModeUiCustomizationSet custom UI for SDK-controlled dark mode challenge UI.Custom object
setDatacenter()Configure which data center the SDK will route to.CardinalDatacenter.VISACardinalDatacenter.CARDINAL, CardinalDatacenter.VISA

6

Initialize Call to Cardinal

Use the CardinalJWT received in the Payer Authentication Setup Step

Calling CardinalService.initialize() will begin the communication process to ensure user experience is seamless, by authenticating your credentials (serverJwt) and completing the data collection process. By the time they are ready to checkout, all necessary pre-processing will be completed. Use the code snippet below for completing the Cardinal.init(). va Code Snippet

Call Cardinal.init in Obecjtive C
NSString *jwtString = @"INSERT_YOUR_JWT_HERE";

[session setupWithJWT:jwtString
didComplete:^(NSString * _Nonnull consumerSessionId){
//
// You may have your Submit button disabled on page load. Once you are setup
// for CCA, you may then enable it. This will prevent users from submitting
// their order before CCA is ready.
//
} didValidate:^(CardinalResponse * _Nonnull validateResponse) {
// Handle failed setup
// If there was an error with setup, cardinal will call this function with
// validate response and empty serverJWT
}];

From the Cardinal SDK response, extract the consumerSessionId to pass into the Payer Authentication Enrollment step.

7

Payer Auth Enrollment

Please see below on how to use the consumerSessionId

Check Enrollment in NodeJS
const safepay = require('@sfpy/node-core')('CLIENT_SIDE_AUTH_TOKEN', {
  authType: 'jwt',
  host: 'https://sandbox.api.getsafepay.com'
});

try {
const response = await safepay.order.tracker.action({
tracker: "track_b65ba6ae-2b11-4606-920b-24d70a2de5c2",
payload: {
billing: {
street_1: "St 1",
street_2: "",
city: "Islamabad",
state: "",
postal_code: "44000",
country: "PK"
},
authorization: {
do_capture: true,
do_card_on_file: false
},
authentication_setup: {
"sdk_reference_id": "<consumerSessionID>"
}
}
});

console.log(response);
} catch (error) {
console.error(error);
}

Note the example above shows a combined authorization and capture without saving the card.

Payer Enrollment Response
{
  "action": {
    "token": "req_29ffd60c-0527-4173-920b-968175deac28",
    "payer_authentication_enrollment": {
      "access_token": "eyJ...",
      "authentication_transaction_id": "BaQGS1iS5DqhxSPWukG0",
      "payload": "eyJtZXNzYWdlVHlwZSI6IkNSZXEi..."
    }
  }
}

8

Create Lookup Response

Create an API call to your backend server in order to send a Lookup Request (cmpi_lookup) to Cardinal's platform for initiating the Consumer Authentication transaction. The Centinel platform manages all of the routing and connectivity, as well as the rules engine for all of the various 3-D Secure protocols and versions. Please follow the Getting Started and Lookup Request/Response sections for completing your backend integration:

Handle the Lookup Response and create the Authentication Session

After the completion of the cmpi_lookup request, check the CMPI_Lookup_Response for the following fields:

  • ThreeDSVersion = 2.X ( 2.0, 2.1, etc)
  • Enrolled = Y
  • PAResStatus = C

Upon validating the above fields, you will call [session continueWithTransactionId.. ] to hand control to SDK for performing the challenge between the user and the issuing bank. Use the code snippet below for completing the session's continue.

In continue for Quick Integration, a class conforming to a protocol CardinalValidationDelegate (and implement a method stepUpDidValidate) should be passed as a parameter. Following is the example of class conforming to CardinalValidationDelegate protocol.

Implement CardinalValidationDelegate in Objective-C
@interface YourViewController () <CardinalValidationDelegate> @end
@implementation YourViewController

(void)cardinalSession:(CardinalSession _)session
stepUpDidValidateWithResponse:(CardinalResponse _)validateResponse
serverJWT:(NSString \*)serverJWT {
// Handle transaction validation result here
}
@end

If continue is being in the same class then the following method is called to start StepUpFlow:

Call continueWithTransactionId in Objective-C
[session continueWithTransactionId:@"[TRANSACTION_ID]"
payload:@"[PAYLOAD]" didValidateDelegate:self]; ```
</SingleCodeBlock>
</Tab>
<Tab id={1}>
<SingleCodeBlock label="Call continueWithTransactionId in Swift">
```swift session.continueWith(transactionId: "[TRANSACTION_ID]", payload:
"[PAYLOAD]", validationDelegate: self) ```
</SingleCodeBlock>
</Tab>
</Tabs>

When the transaction has been terminated, the stepUpDidValidate method is triggered. This is how the Cardinal Mobile SDK hands control back to your application.

This event includes key data about how the transaction attempt concluded, and it’s your responsibility to handle and interpret this information appropriately.

<Callout type="info" icon={InfoIcon}>
- Use the <code>actionCode</code> field from the response to determine the
final outcome of the transaction. - Recommended Handling - On receiving the
callback, review the <code>actionCode</code> to assess the transaction status
and decide the next steps. - If <code>actionCode</code> is either{" "}
<strong>SUCCESS</strong> or <strong>NOACTION</strong>, you should forward the
JWT to your backend for verification.
</Callout>

<Tabs tabs={['Objective C', 'Swift']}>
<Tab id={0}>
<SingleCodeBlock label="Handle challenge results with actionCode in objective-c">
```objective-c

- (void)cardinalSession:(CardinalSession _)session stepUpDidValidateWithResponse:(CardinalResponse _)validateResponse serverJWT:(NSString \*)serverJWT { switch (validateResponse.actionCode) { case CardinalResponseActionCodeSuccess: // Transaction successful — send JWT to backend for verification break;

case CardinalResponseActionCodeNoAction:
    // No action taken by issuer
    break;

case CardinalResponseActionCodeFailure:
    // Authentication failed
    break;

case CardinalResponseActionCodeError:
    // SDK-level or issuer error
    break;

case CardinalResponseActionCodeCancel:
    // User canceled the challenge
    break;

case CardinalResponseActionCodeTimeout:
    // Challenge session timed out
    break;

}
}

On SUCCESS or NOACTION, you should forward the JWT to your backend for verification. See the next section on JWT Verification.

9

JWT Validation

Once the response JWT arrives in the onValidated, you must send it to your backend for verification and consumption.

We recommend that any values shared with third parties are only sourced from the validated JWT.

Security Warning: For security reasons, all JWT validation must be performed on the server side.

For more information, see the JWT Overview.

10

Combined Validation and Authorization (Enrolled Cards)

Execute the PAYER_AUTH_VALIDATION action. Pass the n3 received from the Cardinal SDK.

PAYER_AUTH_VALIDATION Sample Payload
{
  "payload": {
    "is_mobile": true,
    "authorization": {
      "do_capture": false,
      "sdk_on_validate_jwt": "eyJ..."
    }
  }
}

Authorization (Non-Enrolled Cards)

Execute the AUTHORIZATION action. Include the is_mobile flag.

AUTHORIZATION Sample Payload
{
  "payload": {
    "is_mobile": true,
    "authorization": {
      "do_capture": false
    }
  }
}
Sample Response
{
  "authorization_status": "authorized",
  "transaction_id": "txn_67890"
}

11

Cleanup

Failing to implement the cleanup method can cause unintentional memory leaks

Cleanup in Objective C
[cardinalService cleanup];