Xác thực 3DS — iOS
Cake 3DS SDK cho iOS (Cake3DS2) triển khai giao thức EMV 3-D Secure 2.x cho việc xác thực chủ thẻ. Phần lõi của SDK được viết bằng Objective-C, với các public header mà code Swift có thể gọi trực tiếp. SDK thu thập và mã hóa dữ liệu thiết bị. Nó trao đổi các thông điệp thử thách CReq và CRes. Nó hiển thị giao diện thử thách. Nó xử lý các lỗi giao thức. Đặc tả EMVCo yêu cầu SDK giao tiếp trực tiếp với Directory Server (DS) và Access Control Server (ACS).
Chi tiết SDK
| Tên package | Cake3DS2 |
| Phân phối | Swift Package Manager, hoặc một file XCFramework trực tiếp |
| Namespace | Module Cake3DS2, các lớp công khai tiền tố CKDS |
| Giao thức | EMV 3DS 2.1.0, 2.2.0, 2.3.0, và 2.3.1 |
| iOS tối thiểu | 13.0 |
| Ngôn ngữ | Objective-C (phần lõi SDK), có thể gọi từ Swift |
Cài đặt
SDK hỗ trợ hai phương thức cài đặt: Swift Package Manager, hoặc một file XCFramework trực tiếp.
Phương án 1: Swift Package Manager (khuyến nghị)
Bước 1. Thêm package Cake3DS2 vào dự án của bạn. Sử dụng đường dẫn package hoặc URL mà Cake cung cấp.
// Package.swift
dependencies: [
.package(path: "/path/to/cake-3ds-swift-package") // hoặc một git URL mà Cake cung cấp
]Bước 2. Thêm Cake3DS2 làm dependency cho target app của bạn.
.target(
name: "YourApp",
dependencies: ["Cake3DS2"]
)Nếu bạn dùng Xcode thay vì file Package.swift, hãy thêm package qua File > Add Package Dependencies.
Phương án 2: File XCFramework trực tiếp
Bước 1. Sao chép file Cake3DS2.xcframework từ Cake vào dự án của bạn.
Bước 2. Thêm file vào target app của bạn. Trong phần cài đặt General của target, dưới "Frameworks, Libraries, and Embedded Content", đặt thành "Embed & Sign".
File XCFramework cũng cần ba system framework. Thêm các mục sau vào cùng danh sách trong target app của bạn:
UIKit.framework
Security.framework
WebKit.frameworkKhởi tạo SDK
Tạo một instance CKDSThreeDS2Service cho mỗi phiên app. Tạo nó khi app khởi chạy, hoặc trong module dependency injection của bạn. SDK cung cấp hai phương thức khởi tạo.
Phương thức đầu tiên chỉ sử dụng các cài đặt mặc định:
import Cake3DS2
let service = CKDSThreeDS2Service()
let config = CKDSConfigParameters(standardParameters: ())
service.initialize(withConfig: config, locale: nil, uiSettings: nil)Sử dụng phương thức thứ hai khi bạn cần một analytics delegate:
service.initialize(
withConfig: config,
locale: nil,
uiSettings: uiCustomization,
analyticsDelegate: myAnalyticsDelegate
)| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
config | CKDSConfigParameters | Có | Đối tượng cấu hình. Dùng CKDSConfigParameters(standardParameters: ()) trừ khi Cake cung cấp thêm tham số để bạn thêm vào. |
locale | Locale? | Không | Ghi đè locale cho giao diện thử thách. Truyền nil để dùng locale hệ thống. |
uiSettings | CKDSUICustomization? | Không | Tùy chỉnh giao diện cho các màn hình thử thách (xem Tùy chỉnh giao diện thử thách). Truyền nil để dùng CKDSUICustomization.defaultSettings(). |
analyticsDelegate | CKDSAnalyticsDelegate | Chỉ ở phương thức thứ hai | Delegate nhận các sự kiện analytics của thử thách, ví dụ một lần nhấn submit OTP |
| Thành viên | Kiểu | Mô tả |
|---|---|---|
warnings | [CKDSWarning]? | Các cảnh báo phát hiện được trong quá trình khởi tạo, ví dụ thiết bị đã jailbreak hoặc có debugger đính kèm |
Cake3DS2 không có phương thức cleanup ở cấp độ service. Thay vào đó, mỗi CKDSTransaction tự dọn dẹp tài nguyên riêng (xem Tạo một transaction).
Tạo một transaction
Với mỗi thanh toán cần xác thực 3DS, tạo một CKDSTransaction. Cake3DS2 có chứng chỉ tích hợp sẵn cho bảy mạng thẻ. Chỉ cần truyền directoryServerID cho các mạng này:
let transaction = service.createTransaction(
forDirectoryServer: directoryServerId, // ví dụ "A000000003" cho Visa
withProtocolVersion: nil // nil = SDK tự chọn giá trị mặc định (2.2.0)
)| Tham số | Kiểu | Mô tả |
|---|---|---|
directoryServerID | String | Directory Server ID của mạng thẻ (xem bảng bên dưới) |
protocolVersion | String? | Phiên bản giao thức cần dùng. Truyền nil để dùng giá trị mặc định của SDK. |
Đối với một mạng ngoài danh sách tích hợp sẵn, hãy tự cung cấp chứng chỉ của riêng bạn thay thế:
let transaction = service.createTransaction(
forDirectoryServer: directoryServerId,
serverKeyID: serverKeyId, // key tùy chọn từ DS
certificateString: certificateString, // PEM hoặc DER mã hóa base64, public key của DS
rootCertificateStrings: rootCertStrings, // PEM hoặc DER mã hóa base64, chứng chỉ gốc của DS-CA
withProtocolVersion: nil
)| Tham số | Kiểu | Mô tả |
|---|---|---|
directoryServerID | String | Directory Server ID được trả về trong response xác thực |
serverKeyID | String? | Key xác thực bổ sung mà một số Directory Server yêu cầu |
certificateString | String | Chứng chỉ PEM hoặc DER mã hóa base64 chứa public key của DS |
rootCertificateStrings | [String] | Các chứng chỉ gốc PEM hoặc DER của DS-CA mã hóa base64, dùng để kiểm tra nội dung đã ký bởi ACS |
protocolVersion | String? | Phiên bản giao thức cần dùng. Truyền nil để dùng giá trị mặc định của SDK. |
Tùy chỉnh giao diện
Truyền uiSettings một lần, cho service.initialize(withConfig:locale:uiSettings:). createTransaction không nhận tham số tùy chỉnh giao diện. Mọi transaction từ cùng một service instance chia sẻ chung một tùy chỉnh. Xem Tùy chỉnh giao diện thử thách.
Directory Server
Cake3DS2 có chứng chỉ tích hợp sẵn cho các mạng sau:
| Mạng | ID |
|---|---|
| Visa | A000000003 |
| Mastercard | A000000004 |
| American Express | A000000025 |
| Discover | A000000324 |
| Cartes Bancaires | A000000042 |
| Test (RSA) | F055545342 |
| Test (EC) | F155545342 |
Đối với một mạng ngoài danh sách này, hãy tự cung cấp certificateString và rootCertificateStrings của riêng bạn cho createTransaction(forDirectoryServer:serverKeyID:certificateString:rootCertificateStrings:withProtocolVersion:) thay thế.
Lấy tham số authentication request
Trước khi gửi Authentication Request (AReq) đến 3DS Server của bạn, gọi createAuthenticationRequestParameters() cho mỗi transaction:
let params = transaction.createAuthenticationRequestParameters()
// Gửi `params` đến backend của bạn để xây dựng và gửi AReqPhương thức này đồng bộ. Nó trả về ngay lập tức. Cake3DS2 thu thập dữ liệu thiết bị một lần, trong quá trình initialize(withConfig:locale:uiSettings:). Phương thức này chỉ mã hóa dữ liệu đó, và đóng gói nó, cùng với chi tiết SDK, vào một đối tượng CKDSAuthenticationRequestParameters.
| Trường | Mô tả |
|---|---|
deviceData | Thông tin thiết bị, được mã hóa JWE. nil nếu SDK không có dữ liệu thiết bị để báo cáo. |
sdkTransactionIdentifier | ID transaction mà SDK gán cho CKDSTransaction này |
sdkAppIdentifier | UUID định danh cài đặt app này, được tạo bởi SDK |
sdkReferenceNumber | Định danh tham chiếu SDK |
sdkEphemeralPublicKey | Public key EC tạm thời của SDK, dưới dạng chuỗi JWK |
messageVersion | Phiên bản giao thức được chọn cho transaction này |
Backend của bạn đưa các trường này vào AReq. Response từ 3DS Server, ARes, cho biết kết quả. Một kết quả frictionless không cần thêm hành động nào từ SDK. Ngược lại, ARes yêu cầu luồng thử thách.
Khởi chạy thử thách
Cake3DS2 không dùng một launcher dựa trên request. Thay vào đó, hãy tuân theo protocol CKDSChallengeStatusReceiver. Truyền một đối tượng tuân theo protocol này vào doChallenge(with:challengeParameters:challengeStatusReceiver:timeout:).
import Cake3DS2
extension PaymentViewController: CKDSChallengeStatusReceiver {
func transaction(_ transaction: CKDSTransaction, didCompleteChallengeWith completionEvent: CKDSCompletionEvent) {
onAuthenticationSucceeded(completionEvent)
}
func transactionDidCancel(_ transaction: CKDSTransaction) {
onAuthenticationCanceled()
}
func transactionDidTimeOut(_ transaction: CKDSTransaction) {
onAuthenticationTimedOut()
}
func transaction(_ transaction: CKDSTransaction, didErrorWith protocolErrorEvent: CKDSProtocolErrorEvent) {
onProtocolError(protocolErrorEvent.errorMessage)
}
func transaction(_ transaction: CKDSTransaction, didErrorWith runtimeErrorEvent: CKDSRuntimeErrorEvent) {
onRuntimeError(runtimeErrorEvent)
}
}Khi ARes yêu cầu một thử thách, xây dựng CKDSChallengeParameters từ nội dung của nó. Sau đó gọi doChallenge(with:challengeParameters:challengeStatusReceiver:timeout:) trên transaction:
import Cake3DS2
let challengeParameters = CKDSChallengeParameters()
challengeParameters.threeDSServerTransactionID = ares.threeDSServerTransID
challengeParameters.acsTransactionID = ares.acsTransID
challengeParameters.acsReferenceNumber = ares.acsReferenceNumber
challengeParameters.acsSignedContent = ares.acsSignedContent
transaction.doChallenge(
with: presentingViewController,
challengeParameters: challengeParameters,
challengeStatusReceiver: self,
timeout: 5 * 60 // giây. Tối thiểu 5 phút (300 giây).
)| Tham số | Kiểu | Mô tả |
|---|---|---|
presentingViewController | UIViewController | View controller mà SDK dùng để hiển thị màn hình thử thách |
challengeParameters | CKDSChallengeParameters | Thông tin ACS từ ARes. threeDSServerTransactionID, acsTransactionID, acsReferenceNumber, và acsSignedContent đều là bắt buộc. |
challengeStatusReceiver | CKDSChallengeStatusReceiver | Đối tượng nhận kết quả thử thách (xem bảng bên dưới) |
timeout | TimeInterval | Thời gian timeout của thử thách, tính bằng giây. Tối thiểu là 5 phút (300 giây). |
doChallenge(...) xác thực nội dung đã ký bởi ACS dựa trên các chứng chỉ gốc DS-CA. Nó hoàn tất trao đổi khóa Diffie-Hellman (ECDH P-256). SDK sử dụng trao đổi này để mã hóa và giải mã các thông điệp CReq và CRes tiếp theo. Lệnh gọi duy nhất này chạy toàn bộ luồng thử thách. Nó hiển thị màn hình thử thách, và gọi lại challengeStatusReceiver của bạn khi luồng kết thúc.
Màn hình xử lý
Gọi transaction.createProgressViewController(didCancel:) để lấy một view controller với logo DS và một spinner, không có điều khiển hủy trên màn hình. Hiển thị nó sau khi bạn gửi AReq. Đóng nó khi màn hình thử thách xuất hiện. Đặc tả EMVCo yêu cầu Màn Hình Xử Lý này.
CKDSChallengeStatusReceiver
Tuân theo protocol này để nhận trạng thái thử thách khi kết thúc quá trình thử thách:
| Phương thức | Được gọi khi |
|---|---|
transaction(_:didCompleteChallengeWith:) | Quá trình thử thách đã kết thúc. Kiểm tra completionEvent.transactionStatus để biết kết quả mà ACS gửi trong CRes cuối cùng. |
transactionDidCancel(_:) | Chủ thẻ chọn hủy transaction trên màn hình thử thách |
transactionDidTimeOut(_:) | Quá trình thử thách đạt đến khoảng thời gian timeout mà bạn đã truyền cho doChallenge |
transaction(_:didErrorWith:) (với một CKDSProtocolErrorEvent) | SDK nhận được một thông điệp lỗi giao thức EMV 3-D Secure từ ACS (xem Xử lý lỗi) |
transaction(_:didErrorWith:) (với một CKDSRuntimeErrorEvent) | SDK phát hiện một lỗi trong quá trình thử thách nằm ngoài các lỗi giao thức ở trên, ví dụ lỗi mạng hoặc lỗi phân tích dữ liệu |
Hai phương thức khác là tùy chọn:
| Phương thức | Được gọi khi |
|---|---|
transactionDidPresentChallengeScreen(_:) | Transaction hiển thị một màn hình thử thách mới |
dismissChallengeViewController(_:forTransaction:) | Dành riêng cho việc sử dụng nội bộ bởi Cake SDK |
Mọi phương thức đều mang theo instance transaction. Nếu app của bạn chạy nhiều hơn một transaction cùng lúc, hãy dùng giá trị này để khớp callback với transaction tương ứng.
Màn hình thử thách

CKDSChallengeResponseViewController hiển thị màn hình này. CKDSUICustomization mà bạn truyền cho initialize(withConfig:locale:uiSettings:) kiểm soát màu sắc, font chữ, và kiểu nút của nó. Xem Tùy chỉnh giao diện thử thách để biết toàn bộ các tùy chọn.
Luồng frictionless so với luồng thử thách
stateDiagram-v2
[*] --> Created: createTransaction(forDirectoryServer:withProtocolVersion:)
Created --> AuthParams: createAuthenticationRequestParameters()
AuthParams --> Frictionless: ARes, no challenge required
AuthParams --> Challenge: ARes, challenge required
Challenge --> Completed: didCompleteChallengeWith
Challenge --> Canceled: transactionDidCancel
Challenge --> Error: didErrorWith (protocol or runtime event)
Challenge --> TimedOut: transactionDidTimeOut
Frictionless --> [*]
Completed --> [*]
Canceled --> [*]
Error --> [*]
TimedOut --> [*]
Các kiểu giao diện thử thách
ACS quyết định giao diện nào màn hình thử thách sẽ hiển thị. Cake3DS2 expose giá trị này qua transaction.presentedChallengeUIType, sau khi thử thách hoàn tất:
| Giá trị | Mã | Yêu cầu nút Submit | Mô tả |
|---|---|---|---|
text | 01 | Có | Nhập văn bản tự do, ví dụ một mã OTP |
single_select | 02 | Có | Chọn một lựa chọn từ danh sách |
multi_select | 03 | Có | Chọn nhiều lựa chọn từ danh sách |
oob | 04 | Không | Được giải quyết bên ngoài app, ví dụ trong ứng dụng ngân hàng của chủ thẻ |
html | 05 | Không | HTML do ACS cung cấp, hiển thị trong một WKWebView |
html_oob | 06 | Không | Thử thách HTML kết hợp với một hành động tiếp tục out-of-band |
information | 07 | Không | Màn hình thông tin với một nút tiếp tục, không có nhập liệu |
Xử lý lỗi
CKDSProtocolErrorEvent.errorMessage là một đối tượng CKDSErrorMessage. Đối tượng này mô tả lý do CRes thất bại khi kiểm tra hợp lệ:
| Trường | Mô tả |
|---|---|
errorCode | Mã lỗi giao thức (xem bảng bên dưới) |
errorComponent | Component 3-D Secure đã phát hiện lỗi |
errorDescription | Mô tả có thể đọc được bởi con người |
errorDetails | Chi tiết lỗi bổ sung, nếu có |
messageVersion | Định danh phiên bản giao thức |
acsTransactionIdentifier | Định danh transaction do ACS gán, nếu biết |
errorMessageType | Loại thông điệp mà lỗi được phát hiện |
Mã lỗi giao thức
| Mã | Tên | Nguyên nhân kích hoạt |
|---|---|---|
101 | InvalidMessage | SDK nhận được một thông điệp không phải ARes, CRes, hoặc ErrorMessage |
201 | RequiredDataElementMissing | Thiếu một trường bắt buộc trong response từ mạng thẻ |
202 | UnrecognizedCriticalMessageExtension | Có một critical message extension không được hỗ trợ |
203 | InvalidDataElement | Định dạng hoặc giá trị của một trường không hợp lệ |
301 | TransactionIDNotRecognized | ID transaction trong CRes không khớp với CReq |
302 | DataDecryptionFailure | Việc giải mã JWE của CRes thất bại |
402 | Timeout | SDK đạt đến thời gian timeout |
CKDSErrorMessageCode không định nghĩa hằng số có tên cho mã lỗi 102 (UnsupportedMessageVersion) hoặc 207 (ReservedValueRange). Nếu ACS gửi một trong các mã này, SDK vẫn báo cáo nó dưới dạng chuỗi thuần trong errorCode.
SDK tự động thông báo lỗi cho ACS. Đây là một hành động fire-and-forget. Sau đó, Cake3DS2 gọi transaction(_:didErrorWith:) (với một CKDSProtocolErrorEvent) trên app của bạn. Bạn không cần thực hiện thêm hành động nào khác.
CKDSRuntimeErrorEvent mang theo một chuỗi errorCode thuần và một chuỗi errorMessage, cho các lỗi nằm ngoài bảng giao thức ở trên, ví dụ lỗi mạng hoặc lỗi phân tích dữ liệu. Hai giá trị được biết đến là kCKDSRuntimeErrorCodeParsingError và kCKDSRuntimeErrorCodeEncryptionError.
Tùy chỉnh giao diện thử thách
Bạn có thể xây dựng một CKDSUICustomization theo hai cách.
Phương án 1: CKDSUICustomization.defaultSettings()
CKDSUICustomization.defaultSettings() cung cấp cho bạn theme design-system của Cake, đã được thiết lập sẵn. Mọi màu sắc, font chữ, và bán kính bo góc đều có giá trị mặc định.
let uiCustomization = CKDSUICustomization.defaultSettings()Sử dụng tùy chọn này để khớp với giao diện checkout mặc định của Cake. Bạn vẫn có thể ghi đè từng phần riêng lẻ sau đó, như ví dụ bên dưới cho thấy.
Phương án 2: Tùy chỉnh thủ công
Tự xây dựng từng đối tượng tùy chỉnh, và gán nó cho một instance CKDSUICustomization mới:
let uiCustomization = CKDSUICustomization()
uiCustomization.navigationBarCustomization = CKDSNavigationBarCustomization.defaultSettings()
uiCustomization.labelCustomization = CKDSLabelCustomization.defaultSettings()
uiCustomization.textFieldCustomization = CKDSTextFieldCustomization.defaultSettings()
uiCustomization.footerCustomization = CKDSFooterCustomization.defaultSettings()
uiCustomization.selectionCustomization = CKDSSelectionCustomization.defaultSettings()Sử dụng tùy chọn này khi bạn cần toàn quyền kiểm soát màn hình thử thách.
Tùy chỉnh từng phần
CKDSUICustomization chứa năm đối tượng lồng nhau: một cho navigation bar, một cho label, một cho text field, một cho footer, và một cho radio button và checkbox. Nút sử dụng một tùy chỉnh riêng, mỗi loại cho một CKDSUICustomizationButtonType. Ví dụ bên dưới bắt đầu từ defaultSettings() (Phương án 1) và ghi đè các phần cụ thể:
import Cake3DS2
let uiCustomization = CKDSUICustomization.defaultSettings()
uiCustomization.backgroundColor = .white
let navigationBar = CKDSNavigationBarCustomization.defaultSettings()
navigationBar.barTintColor = UIColor(red: 0.10, green: 0.10, blue: 0.10, alpha: 1)
navigationBar.headerText = "Secure Checkout"
navigationBar.buttonText = "CANCEL"
navigationBar.textColor = .white
uiCustomization.navigationBarCustomization = navigationBar
let labels = CKDSLabelCustomization.defaultSettings()
labels.headingTextColor = .black
labels.textColor = UIColor(white: 0.2, alpha: 1)
uiCustomization.labelCustomization = labels
let textField = CKDSTextFieldCustomization.defaultSettings()
textField.borderColor = UIColor(white: 0, alpha: 0.5)
textField.borderWidth = 2
textField.cornerRadius = 8
uiCustomization.textFieldCustomization = textField
let submitButton = CKDSButtonCustomization.defaultSettings(for: .submit)
submitButton.backgroundColor = UIColor(red: 1.0, green: 0.42, blue: 0.0, alpha: 1)
submitButton.cornerRadius = 8
uiCustomization.setButton(submitButton, for: .submit)
uiCustomization.setButton(submitButton, for: .next)
uiCustomization.setButton(submitButton, for: .continue)
let cancelButton = CKDSButtonCustomization.defaultSettings(for: .cancel)
cancelButton.backgroundColor = UIColor(red: 0.93, green: 0.28, blue: 0.28, alpha: 1)
uiCustomization.setButton(cancelButton, for: .cancel)Màu sắc và font chữ
Các setter của Cake3DS2 nhận giá trị UIColor và UIFont gốc, không phải chuỗi hex. Hãy tự xây dựng mỗi UIColor từ helper hex riêng của bạn, hoặc từ UIColor(red:green:blue:alpha:).
CKDSNavigationBarCustomization
| Thuộc tính | Đặt |
|---|---|
barTintColor | Màu nền của navigation bar |
barStyle | Kiểu thanh của navigation bar |
translucent | Navigation bar có trong suốt hay không |
scrollEdgeAppearance | Giao diện của navigation bar tại mép cuộn |
headerText | Văn bản tiêu đề hiển thị trong navigation bar |
buttonText | Văn bản của nút hủy trong navigation bar |
font / textColor | Font và màu của văn bản tiêu đề và văn bản nút |
CKDSLabelCustomization
| Thuộc tính | Đặt |
|---|---|
headingTextColor | Màu của văn bản tiêu đề |
headingFont | Font của văn bản tiêu đề |
font / textColor | Font và màu của văn bản label chính |
CKDSTextFieldCustomization
| Thuộc tính | Đặt |
|---|---|
borderWidth | Độ dày viền của ô nhập liệu |
borderColor | Màu viền của ô nhập liệu |
cornerRadius | Bán kính bo góc của ô nhập liệu |
keyboardAppearance | Giao diện bàn phím cho ô nhập liệu |
placeholderTextColor | Màu của văn bản gợi ý (hint) |
font / textColor | Font và màu của văn bản mà chủ thẻ nhập |
CKDSFooterCustomization
| Thuộc tính | Đặt |
|---|---|
backgroundColor | Màu nền của footer có thể mở rộng |
chevronColor | Màu của mũi tên mở/thu gọn |
headingTextColor | Màu của văn bản tiêu đề footer |
headingFont | Font của văn bản tiêu đề footer |
CKDSSelectionCustomization
| Thuộc tính | Đặt |
|---|---|
primarySelectedColor | Màu chính của trạng thái đã chọn |
secondarySelectedColor | Màu phụ của trạng thái đã chọn, ví dụ dấu tick |
unselectedBackgroundColor | Màu nền ở trạng thái chưa chọn |
unselectedBorderColor | Màu viền ở trạng thái chưa chọn |
CKDSButtonCustomization
| Thuộc tính | Đặt |
|---|---|
backgroundColor | Màu nền của nút |
cornerRadius | Bán kính bo góc của nút |
titleStyle | Biến đổi chữ hoa/thường cho tiêu đề nút: .default, .uppercase, .lowercase, hoặc .sentenceCapitalized |
font / textColor | Font và màu của văn bản nút |
Đặt một CKDSButtonCustomization cho mỗi loại nút bạn muốn tùy chỉnh. CKDSUICustomizationButtonType định nghĩa bảy giá trị: .submit, .continue, .next, .cancel, .resend, .openOOBApp, và .addChoice.
Truyền uiCustomization kết quả vào service.initialize(withConfig:locale:uiSettings:).
Sơ đồ luồng đầy đủ
sequenceDiagram
participant App as Merchant App
participant SDK as 3DS SDK
participant ACS as Issuer ACS
App->>SDK: CKDSThreeDS2Service().initialize(withConfig:locale:uiSettings:)
SDK-->>App: warnings, if any
App->>SDK: createTransaction(forDirectoryServer:withProtocolVersion:)
SDK-->>App: CKDSTransaction
App->>SDK: createAuthenticationRequestParameters()
SDK-->>App: CKDSAuthenticationRequestParameters
Note over App: Send AReq to your 3DS Server, receive ARes
alt Frictionless
Note over App: ARes indicates no challenge is needed
else Challenge required
App->>SDK: doChallenge(with:challengeParameters:challengeStatusReceiver:timeout:)
SDK->>ACS: Validate ACS-signed content, key exchange, initial CReq
ACS-->>SDK: Initial CRes
Note over SDK: Presents the challenge screen
SDK->>ACS: Remaining CReq and CRes exchange
ACS-->>SDK: Challenge result
SDK-->>App: didComplete, didCancel, didTimeOut, or didError on CKDSChallengeStatusReceiver
end