Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commit Checkout OOB SDK for version 1.1.0 #23

Merged
merged 4 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions .github/partial-readmes/OOB-SDK-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
![Checkout.com](https://github.com/checkout/frames-ios/blob/main/.github/media/checkout-logo.png)

Checkout.com’s Out-of-Band (OOB) Authentication SDK enables iOS apps to authenticate users for digital transactions (3DS). Our OOB SDK enables you to offer a modern 3DS challenge method alongside existing challenge types, such as OTP.

OOB involves utilising a secondary factor, such as your phone’s banking app, to authenticate a payment and encompasses the fundamental processes of device binding and transaction authentication. Our OOB SDK is focused on this use case.

***

# Table of Contents
- [Environments](#Environments)
- [Integration](#Integration)
- [Import SDK](#Import-SDK)
- [Register Device](#Register-Device)
- [Authenticate Payment](#Authenticate-Payment)
- [Other requirements](#Other-requirements)
- [Building the UI](#Building-the-UI)
- [Listening to webhooks](#Listening-to-webhooks)
- [Performing SCA as requested](#Performing-SCA-as-requested)

***

# Environments
The iOS SDK supports the following environments: Sandbox and Production. You’ll define the environment to use when you initialise the SDK.

To use Sandbox and Production environments, you must have [begun onboarding for card issuing](https://www.checkout.com/docs/card-issuing/get-started-with-issuing) with Checkout.com. During your onboarding, you'll receive client credentials, which you'll need to handle on your back end for authentication to access the environments.

***

# Requirements
- The SDK is provided as a native Swift package. If you're working on a hybrid project, consult your hybrid platform's documentation for instructions on integrating native third-party SDKs.

- It's important to ensure Strong Customer Authentication (SCA) is enabled for your users. While we handle various security measures, you're responsible for performing SCA on your users as specified.

- Each authentication session has the ability to generate multiple tokens simultaneously for various systems. For instance, for sign-in purposes or to obtain an SDK session token or an internal authentication token. However, only one SDK token can be generated from each SCA flow requested.

***
# Integration

### Import SDK
Our SDK is designed to seamlessly integrate with all our backend services for features relevant to OOB authentication. Whether you're registering a device for OOB or authenticating payments via your iOS app, our SDK simplifies the process, making it effortless for you to offer this functionality to your users.

Import the SDK into your app using Swift Package Manager (SPM):

1. Open Xcode and navigate to `Project -> Package Dependencies`.
2. When prompted, enter the URL: https://github.com/checkout/CheckoutCardManagement-iOS.git
3. Select `Up to Next Major Version` as below
<img width="671" alt="Screenshot 2024-03-27 at 17 03 39" src="https://github.com/cko-mobile/OOB-iOS/assets/125963311/3df43958-f696-4645-a0e2-c7d0af911a10">

4. Click on `Add Package`
5. You'll be presented with these options:
<img width="773" alt="Screenshot 2024-03-27 at 17 05 17" src="https://github.com/cko-mobile/OOB-iOS/assets/125963311/52fd9674-7b71-4065-b3f3-b09ab6e0f398">

6. If you just want to use OOB SDK as a standalone SDK and no other product from Checkout.com, select your main target to include `CheckoutOOBSDK` as below. If you also want to use Checkout.com's Issuing solution ([CheckoutCardManagement](https://github.com/checkout/CheckoutCardManagement-iOS)), then follow the instructions in its README. (See an example [here](https://github.com/checkout/CheckoutCardManagement-iOS/tree/main/Sample%20Application))
<img width="768" alt="Screenshot 2024-03-27 at 17 06 03" src="https://github.com/cko-mobile/OOB-iOS/assets/125963311/ad53127c-5821-4b62-a08c-cc1ab7d7a2bf">

7. Click on `Add Package` again.
8. You have to add [CheckoutNetwork](https://github.com/checkout/NetworkClient-iOS) as a dependency to your project as well. Use `https://github.com/checkout/NetworkClient-iOS.git` for that
9. For an example, see our [SampleApplication](https://github.com/checkout/CheckoutCardManagement-iOS/tree/main/Sample%20Application)'s configuration under `Project -> Package Dependencies` thereof.
10. Refer to Apple's documentation on adding a SPM dependency for detailed instructions.

To begin utilising the SDK functionality, initialise the primary object, granting access to its features:

```Swift
import CheckoutOOBSDK

// Initialise the SDK with preferred environment
let checkoutOOB = CheckoutOOB(environment: .sandbox)
```

### Register Device
This is the first core flow whereby the device and app must be registered for OOB. Note that a given card can only be registered for OOB for a single device/app combination. If you register another device for the same card it will overwrite the previously bound device/app combination.

The register device stage can likely be done as a background process during onboarding of a user in your iOS app, but you could offer a button that enables a user to do this manually if you wish. Note that before registering a device/app/card combination for OOB, you must perform SCA on the cardholder.

To establish device binding, register your cardholder's mobile device as follows:

```Swift
// You must be in an async context to call SDK's async functions.
// You can use a Task for that.
Task {
do {
let deviceRegistration = try CheckoutOOB.DeviceRegistration(token: "access_token",
cardID: "card_id", // 30 characters
applicationID: "application_id", // Most probably your notification token. Communicate with your backend to figure it out.
phoneNumber: CheckoutOOB.PhoneNumber(countryCode: "+44", number: "5006007080"),
locale: .english) // Other option is `.french`

try await checkoutOOB.registerDevice(with: deviceRegistration)

} catch {
print(error.localizedDescription)
}
}
```

### Authenticate Payment
This is the core authentication flow where the user will approve or reject the transaction within your iOS app. This flow will begin from our card issuing backend, where you will need to listen to the webhook provided to obtain transaction details to inject into the SDK (more on webhooks later).

Note that before authenticating a payment using OOB, you must perform SCA on the cardholder.


Once you have the data from your backend, verify online card transactions made by your cardholders like so:

```Swift
Task {
do {
let paymentAuthentication = try CheckoutOOB.Authentication(token: "access_token",
cardID: "card_id", // 30 characters
transactionID: "transaction_id",
method: .biometrics,
decision: .accepted)

try await checkoutOOB.authenticatePayment(with: paymentAuthentication)

} catch {
print(error.localizedDescription)
}
}
```
***

# Other requirements
### Building the UI
Our SDK remains light on UI objects so that you can create the experience you desire. You will therefore need to build the UI for the transaction authentication screen (the screen that shows during the _authenticate payment_ stage), as well as any associated UI (if you wish so) for the _register device_ process.

### Listening to webhooks
***
(Only read if you are developing the backend support for your application's OOB functionality, if you're solely a mobile developer, disregard this section)
***
In order to obtain transaction information to inject into our SDK, you must be able to listen to webhooks from our issuing backend. We recommend that you implement a push notification to the mobile app and use the data from the webhook to inform the cardholder about the details of the transaction they are authenticating for.

You should provide an endpoint that receives a HTTP POST and returns a 200 OK response on receipt of the webhook. The transaction will not complete unless we receive acknowledgement.

The JSON payload you should expect looks like this:
```json
{
"acsTransactionId": "bea260bb-c183-4d74-8bc9-421fe3aa2658",
"cardId": "ea3ze38kfj3g6ktv6wn14aaylvmdv3qn",
"applicationId": "ios-4283-23344-7884ea-474752",
"transactionDetails": {
"maskedCardNumber": "**** **** **** 1234",
"purchaseDate": "2024-12-24T17:32:28.000Z",
"merchantName": "ACME Corporation",
"purchaseAmount": 1,
"purchaseCurrency": "GBP"
},
"threeDSRequestorAppURL": "https://requestor.netcetera.com?transID=bea260bb-c183-4d74-8bc9-421fe3aa2658"
}

```

The _applicationId_ property is used to identify which mobile app to send a push notification to.

We will also provide a webhook in the event that the transaction is cancelled, due to timeout or any other cause. We also expect a 200 OK acknowledgement for this webhook. In this case, the JSON payload will look like this:

```json
{
"transactionId": "bea260bb-c183-4d74-8bc9-421fe3aa2658"
}
```

In both cases we will also include an `Authorization` header in the request containing the value provided to us at client onboarding. This is used to verify that the request comes from us.

For any questions on onboarding, please speak to your issuing representative or contact [email protected].

### Performing SCA as requested
You must perform SCA (strong customer authentication) on the cardholder before device registration and payment authentication flows. This would likely be when the user enters the app, but could be at other stages.
8 changes: 7 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "CheckoutCardManagement-iOS",
platforms: [
.iOS(.v12),
.iOS(.v13),
],
products: [
.library(
Expand All @@ -15,6 +15,9 @@ let package = Package(
.library(
name: "CheckoutCardManagementStub",
targets: ["CheckoutCardManagementStub"]),
.library(
name: "CheckoutOOBSDK",
targets: ["CheckoutOOBSDK"]),
],
dependencies: [
.package(
Expand Down Expand Up @@ -44,5 +47,8 @@ let package = Package(
.binaryTarget(
name: "CheckoutCardNetworkStub",
path: "SupportFrameworks/CheckoutCardNetworkStub.xcframework"),
.binaryTarget(
name: "CheckoutOOBSDK",
path: "SupportFrameworks/CheckoutOOBSDK.xcframework"),
]
)
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- [What is the CheckoutCardManagement-iOS SDK?](#What-is-the-CheckoutCardManagement-iOS-SDK)
- [Environments](#Environments)
- [Migrating from Stub to Sandbox and Production](#Migrating_from_Stub_to_Sandbox_and_Production)
- [Sample Application](#Sample-application)
- [Features](#Features)
- [Requirements](#Requirements)
- [Integration](#Integration)
Expand All @@ -12,6 +13,7 @@
- [Update card state](#Update-card-state)
- [Retrieve Secure Data](#Retrieve-secure-data)
- [Push Provisioning](#Push-provisioning)
- [Out of Band (OOB) Authentication](##checkout-out-of-band-oob-authentication-sdk)
- [Contact](#Contact)
***

Expand Down Expand Up @@ -226,6 +228,10 @@ There are some behaviors to be aware of when you attempt a push provisioning ope
- in the sandbox Checkout.com environment, you'll receive a `pushProvisioningFailure` error, as push provisioning is only valid in production
- in the production Checkout.com environment, you'll receive an `OperationResult` success message

***
# Checkout Out of Band (OOB) Authentication SDK
Please find documentation [here](https://github.com/checkout/CheckoutCardManagement-iOS/blob/main/.github/partial-readmes/OOB-SDK-README.md).

***
# Contact
For Checkout.com issuing clients, please email [email protected] for any questions.
56 changes: 32 additions & 24 deletions Sample Application/SampleApplication.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
16725FD42A1CCE9E00910DC5 /* Authenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16725FD32A1CCE9E00910DC5 /* Authenticator.swift */; };
16725FD62A1CD83200910DC5 /* NetworkEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16725FD52A1CD83200910DC5 /* NetworkEndpoint.swift */; };
16925A542A1FA96200C44AAF /* AuthenticationValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16925A532A1FA96200C44AAF /* AuthenticationValidator.swift */; };
16D74E5C2A27AE4B005F2157 /* CheckoutNetwork in Frameworks */ = {isa = PBXBuildFile; productRef = 16D74E5B2A27AE4B005F2157 /* CheckoutNetwork */; };
16D74E5F2A27AE67005F2157 /* CheckoutCardManagementStub in Frameworks */ = {isa = PBXBuildFile; productRef = 16D74E5E2A27AE67005F2157 /* CheckoutCardManagementStub */; };
169D837B2BB47A1500ABAD50 /* CheckoutCardManagementStub in Frameworks */ = {isa = PBXBuildFile; productRef = 169D837A2BB47A1500ABAD50 /* CheckoutCardManagementStub */; };
169D837D2BB47A1500ABAD50 /* CheckoutOOBSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 169D837C2BB47A1500ABAD50 /* CheckoutOOBSDK */; };
169D83802BB47A2700ABAD50 /* CheckoutNetwork in Frameworks */ = {isa = PBXBuildFile; productRef = 169D837F2BB47A2700ABAD50 /* CheckoutNetwork */; };
16F7C87929C22A9000ECB801 /* SampleApplicationApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F7C87829C22A9000ECB801 /* SampleApplicationApp.swift */; };
16F7C87D29C22A9200ECB801 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 16F7C87C29C22A9200ECB801 /* Assets.xcassets */; };
16F7C89529C22A9200ECB801 /* SampleApplicationUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F7C89429C22A9200ECB801 /* SampleApplicationUITests.swift */; };
Expand Down Expand Up @@ -100,9 +101,10 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
169D837D2BB47A1500ABAD50 /* CheckoutOOBSDK in Frameworks */,
16F7C8A829C22BA200ECB801 /* SwiftJWT in Frameworks */,
16D74E5C2A27AE4B005F2157 /* CheckoutNetwork in Frameworks */,
16D74E5F2A27AE67005F2157 /* CheckoutCardManagementStub in Frameworks */,
169D837B2BB47A1500ABAD50 /* CheckoutCardManagementStub in Frameworks */,
169D83802BB47A2700ABAD50 /* CheckoutNetwork in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -288,8 +290,9 @@
name = SampleApplication;
packageProductDependencies = (
16F7C8A729C22BA200ECB801 /* SwiftJWT */,
16D74E5B2A27AE4B005F2157 /* CheckoutNetwork */,
16D74E5E2A27AE67005F2157 /* CheckoutCardManagementStub */,
169D837A2BB47A1500ABAD50 /* CheckoutCardManagementStub */,
169D837C2BB47A1500ABAD50 /* CheckoutOOBSDK */,
169D837F2BB47A2700ABAD50 /* CheckoutNetwork */,
);
productName = SampleApplication;
productReference = 16F7C87529C22A9000ECB801 /* SampleApplication.app */;
Expand Down Expand Up @@ -343,8 +346,8 @@
mainGroup = 16F7C86C29C22A9000ECB801;
packageReferences = (
16F7C8A629C22BA200ECB801 /* XCRemoteSwiftPackageReference "Swift-JWT" */,
16F7C8A929C22BF500ECB801 /* XCRemoteSwiftPackageReference "NetworkClient-iOS" */,
16D74E5D2A27AE67005F2157 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */,
169D83792BB47A1500ABAD50 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */,
169D837E2BB47A2700ABAD50 /* XCRemoteSwiftPackageReference "NetworkClient-iOS" */,
);
productRefGroup = 16F7C87629C22A9000ECB801 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -711,42 +714,47 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
16D74E5D2A27AE67005F2157 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */ = {
169D83792BB47A1500ABAD50 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "git@github.com:checkout/CheckoutCardManagement-iOS.git";
repositoryURL = "https://github.com/checkout/CheckoutCardManagement-iOS.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
minimumVersion = 1.1.0;
};
};
16F7C8A629C22BA200ECB801 /* XCRemoteSwiftPackageReference "Swift-JWT" */ = {
169D837E2BB47A2700ABAD50 /* XCRemoteSwiftPackageReference "NetworkClient-iOS" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Kitura/Swift-JWT.git";
repositoryURL = "https://github.com/checkout/NetworkClient-iOS";
requirement = {
branch = master;
kind = branch;
kind = upToNextMajorVersion;
minimumVersion = 1.1.2;
};
};
16F7C8A929C22BF500ECB801 /* XCRemoteSwiftPackageReference "NetworkClient-iOS" */ = {
16F7C8A629C22BA200ECB801 /* XCRemoteSwiftPackageReference "Swift-JWT" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "git@github.com:checkout/NetworkClient-iOS.git";
repositoryURL = "https://github.com/Kitura/Swift-JWT.git";
requirement = {
branch = main;
branch = master;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
16D74E5B2A27AE4B005F2157 /* CheckoutNetwork */ = {
169D837A2BB47A1500ABAD50 /* CheckoutCardManagementStub */ = {
isa = XCSwiftPackageProductDependency;
package = 16F7C8A929C22BF500ECB801 /* XCRemoteSwiftPackageReference "NetworkClient-iOS" */;
productName = CheckoutNetwork;
package = 169D83792BB47A1500ABAD50 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */;
productName = CheckoutCardManagementStub;
};
16D74E5E2A27AE67005F2157 /* CheckoutCardManagementStub */ = {
169D837C2BB47A1500ABAD50 /* CheckoutOOBSDK */ = {
isa = XCSwiftPackageProductDependency;
package = 16D74E5D2A27AE67005F2157 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */;
productName = CheckoutCardManagementStub;
package = 169D83792BB47A1500ABAD50 /* XCRemoteSwiftPackageReference "CheckoutCardManagement-iOS" */;
productName = CheckoutOOBSDK;
};
169D837F2BB47A2700ABAD50 /* CheckoutNetwork */ = {
isa = XCSwiftPackageProductDependency;
package = 169D837E2BB47A2700ABAD50 /* XCRemoteSwiftPackageReference "NetworkClient-iOS" */;
productName = CheckoutNetwork;
};
16F7C8A729C22BA200ECB801 /* SwiftJWT */ = {
isa = XCSwiftPackageProductDependency;
Expand Down
44 changes: 44 additions & 0 deletions SupportFrameworks/CheckoutOOBSDK.xcframework/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AvailableLibraries</key>
<array>
<dict>
<key>BinaryPath</key>
<string>CheckoutOOBSDK.framework/CheckoutOOBSDK</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>CheckoutOOBSDK.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>CheckoutOOBSDK.framework/CheckoutOOBSDK</string>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>CheckoutOOBSDK.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Loading
Loading