How to integrate the SDK in your application

v2.x

Introducing the software documentation and the demo app!

The software documentation provides elaborated information on every class, function and member in the SDK. The class documentation is a .doccarchive file that can be opened with Xcode. To get it, please follow those steps:

  1. Open the tag list in the SDK repo.
  2. Select the wanted version.
  3. Download the source code (zip file).
  4. Unzip the file and open the PerimeterX_SDK.doccarchive file via Xcode.

The demo app gives you a general idea on how you should implement the SDK in you app. To download it, please follow those steps:

  1. Open the demo app repo.
  2. Download the content of the repo.
  3. Unzip the file and open the iOS demo app.

Prerequisites

The following are required to install the SDK:

  1. Administrative access to the HUMAN Portal to:
    1. Retrieve the HUMAN application ID (AppID).
    2. Set the token expiration and validity.
  2. An active HUMAN Enforcer.

Choose the HUMAN SDK version according to your development environment:

Xcode 15.1
Swift 5.9
Xcode 13.4
Swift 5.6
Xcode 13.3
Swift 5.6
Xcode 13.0 - 13.2
Swift 5.5

Adding HUMAN SDK to your project:

You can add the SDK to your project with one of the following options:

Swift Package Manager

Add the package from the following repository: https://github.com/PerimeterX/px-iOS-Framework

CocoaPods

Add the HUMAN pod to your Podfile.

platform :ios, '13.0'
use_frameworks!

target '<Your App Name>' do
    pod 'PerimeterX', '<version>'
end

Manual

  1. Open the SDK repo.
  2. Download the content of the repo.
  3. Unzip the file and copy the PerimeterX_SDK.xcframework file to you project.
  4. In Xcode, add the framework to the "Frameworks and Libraries" section in your target.

How to start the SDK

Starting the SDK should be the first thing that runs in your app. Therefore, you should start it in your AppDelegate class:

  1. Import the SDK.

    import PerimeterX_SDK
    

    @import PerimeterX_SDK;
    
  2. Make the AppDelegate class to conform to the PerimeterXDelegate. Implement all functions in the protocol.

    class AppDelegate: UIResponder, UIApplicationDelegate, PerimeterXDelegate
    

    @interface AppDelegate : UIResponder <UIApplicationDelegate, PerimeterXDelegate>
    
  3. Call the PerimeterX/start(appId:delegate:enableDoctorCheck:completion:) function with your AppID in the UIApplicationDelegate's didFinishLaunchingWithOptionsfunction.

    PerimeterX.start(appId: "<APP_ID>", delegate: self, enableDoctorCheck: false) { success, error in
        if !success {
            // make sure to start the sdk again when it fails (network issue, etc.)
        }
    }
    

    [PerimeterX startWithAppId:@"<APP_ID>" delegate:self enableDoctorCheck:NO completion:^(BOOL success, NSError * _Nullable error) {
            if (!success) {
                // make sure to start the sdk again when it fails (network issue, etc.)
            }
        }];
    
  4. You can set the SDK's policy to configure custom configurations and behaviors:

    let policy = PXPolicy()
    // configure the policy instacne
    PerimeterX.setPolicy(policy: policy, forAppId: nil, completion: nil)
    

    PXPolicy *policy = [[PXPolicy alloc] init];
    // configure the policy instacne
    [PerimeterX setPolicyWithPolicy:policy forAppId:nil completion:nil];
    

That's it! 🎉 Your code should be like this:

PerimeterX.start(appId: "<APP_ID>", delegate: self, enableDoctorCheck: false) { success, error in
    if !success {
        // start the sdk again when it fails (network issue, etc.)
    }
}

let policy = PXPolicy()
// configure the policy instacne
PerimeterX.setPolicy(policy: policy, forAppId: nil, completion: nil)
[PerimeterX startWithAppId:@"<APP_ID>" delegate:self enableDoctorCheck:NO completion:^(BOOL success, NSError * _Nullable error) {
    if (!success) {
        // start the sdk again when it fails (network issue, etc.)
    }
}];

PXPolicy *policy = [[PXPolicy alloc] init];
// configure the policy instacne
[PerimeterX setPolicyWithPolicy:policy forAppId:nil completion:nil];

How to include SDK’s headers in your URL requests

SDK's headers must be included in your URL requests. To your delight, the SDK is automatically intercepts URL requests from your app which based on URL Session (including Alamofire). By doing so, the SDK takes care of adding those headers to your URL requests, which means you don't have to do anything else.

However, you may choose to include those headers by yourself. To do so, please follow those steps:

  1. You can disable requests interception by setting the PXPolicy/requestsInterceptedAutomaticallyEnabled to false. You must set this before calling the PerimeterX/start(appId:delegate:enableDoctorCheck:completion:)function.

    PXPolicy.requestsInterceptedAutomaticallyEnabled = false
    
    // call the start function...
    

    PXPolicy.requestsInterceptedAutomaticallyEnabled = NO;
    
    // call the start function...
    

  2. In the policy instance, set the PXPolicy/requestsInterceptedAutomaticallyEnabled to false:

    policy.requestsInterceptedAutomaticallyEnabled = false
    

    policy.requestsInterceptedAutomaticallyEnabled = NO;
    

  3. Before sending your URL request, take HTTP headers from the SDK and add them to your request. The SDK should always return headers. When no headers are returned, it means that something went wrong with the SDK integration.

    let headers = PerimeterX.headersForURLRequest(forAppId: nil)
    
    // add those headers to your URL request
    

    NSDictionary<NSString *, NSString *> *headers = [PerimeterX headersForURLRequestForAppId:nil];
    
    // add those headers to your URL request
    

🚧

Don't cache headers!

You should not cache those headers. Those headers contain a token with expiration data. The SDK manages this token to be up-to-date.

How to handle the block response from the server

To your delight, the SDK is automatically intercepts URL requests from your app which based on URL Session (including Alamofire). By doing so, the SDK takes care of handling the block response from your server, which means you don't have to do anything else.

You can verify the error object that was received with those APIs:

  1. PerimeterX/isRequestBlockedError(error:) - the request was blocked; Called immediately when the response from the server reach the device.
  2. PerimeterX/isChallengeSolvedError(error:) - the request was blocked and the user solved the challenge; Called after the user solved the challenge.
  3. PerimeterX/isChallengeCancelledError(error:) - the request was blocked and the user cancelled the challenge; Called after the user cancelled the challenge.

If you are using Alamofire, you should pass the AFError.underlyingError object to those functions. Here is an example:

if let error = response.error?.underlyingError {
	let isRequestBlockedError = PerimeterX.isRequestBlockedError(error: error)
	if isRequestBlockedError {
		print("request was blocked by PX")
	}
}

However, if you choose to include headers from the SDK to your URL request manually, you have to provide the SDK with the response as well:
After receiving an error in the response, pass the information to SDK:

let isHandledByPX = PerimeterX.handleResponse(forAppId: nil, data: data, response: response)
BOOL isHandledByPX = [PerimeterX handleResponseForAppId:nil data:data response:response];

Hybrid App support

The hybrid App uses both native URL requests and web views to communicate with the server. In the context of HUMAN, it's important to make sure both native requests and web views are synced together to make sure end users will get the expected behavior from your app. To help the SDK achieve that, you should set your domain in the policy for the relevant AppID. Here is an example:

policy.domains.insert("my-domain.com")
policy.domains = [NSSet setWithObject:@"my-domain.com"];

If your app using Apple Pay on the Web you should disable JavaScript evaluation by the SDK. In order to protect the security of Apple Pay transactions in WKWebView, Apple Pay cannot be used alongside of script injection APIs. You can do this by setting the policy. Here is an example:

policy.allowJavaScriptEvaluation = false
policy.allowJavaScriptEvaluation = NO;

You can turn off the hybrid app support by setting the PXPolicy/hybridAppSupportEnabled to false. You must set this before calling the PerimeterX/start(appId:delegate:enableDoctorCheck:completion:) function.

PXPolicy.hybridAppSupportEnabled = false

// call the start function...
PXPolicy.hybridAppSupportEnabled = NO;

// call the start function...

Enable support for Account Defender

In order to enable Account Defender, a user ID must be set. You can set it by calling the PerimeterX/setUserId(userId:forAppId:) function with a non nil value. When the current user logout, you should call this function again with nil. This will turn off the Account Defender.

PerimeterX.setUserId(userId: "<the current user ID>", forAppId: nil)
[PerimeterX setUserIdWithUserId:@"<the current user ID>" forAppId:nil];

In order to tell Account Defender about the user's flow, you should call this function for each URL request that been send to your server. Notice that when the PXPolicy/requestsInterceptedAutomaticallyEnabled is set to true, the SDK registers URL requests automatically and you don't need to call this function.

PerimeterX.registerOutgoingUrlRequest(url: "<URL>", forAppId: nil)
[PerimeterX registerOutgoingUrlRequestWithUrl:@"<URL>" forAppId:nil];

Understanding how the SDK works

What happens when you start the SDK

The PerimeterX/start(appId:delegate:enableDoctorCheck:completion:) function sets up the session for a given AppID. Without setting up the session, most APIs in the SDK won't work (for example, set policy or get headers). Notice that you don't need to wait until the completion handler is called in order to call other APIs. When the process ends successfully, the completion handler is called with success as true. However, this process can fail due to network issue. In this case, you should call the function again (we recommend waiting one second before calling it again).

When you call the PerimeterX/start(appId:delegate:enableDoctorCheck:completion:) function, the SDK is creating a background thread to perform its work. You don't need to worry about any performance issue when calling it from the main thread.

While this function is working in the background, the SDK will still provide the required headers. It's essential to call this function as early as possible in your application and before any URL request to your server.

What is included in the SDK's headers

The headers includes a token that allow your server to verify that the URL request comes from your app, which running the SDK. The SDK receives this token from HUMAN's backend when you call the PerimeterX/start(appId:delegate:enableDoctorCheck:completion:) function. Every few minutes the SDK communicates with HUMAN's backend to get a new token.

However, you don't need to verify that the token is exists in the headers. For example, when sending a request while the SDK is starting, the SDK's header will have an indication that the token is not available yet. This case is relevant for the first time you app launches on a device, because the token is saved persistently in the SDK and will used in the next app launch.

How the SDK presents the block page to the user

When the SDK receives the block response from the server it performs the following actions:

  1. Presenting a block view controller in the app, over your other controllers.
  2. In the block view controller the SDK presents a web view which loads the challenge that must be solved by the user (or the bot).
  3. Once the challenge is solved, the SDK removes the block view controller and allow the user to continue working in your app.

Next steps

Review the following topics: