Native - Easiest Implementation

Introduction

  • In this article we will learn how to integrate the SDK to your native iOS/Android app.

  • Highlights:

    • The faster way to integrate the SDK - minimum integration points.
    • The SDK intercepts your URL requests.
    • Handle blocked requests.
  • Note that the Android implementation requires that your app use OkHttp which supports Interceptors.

  • Note that the iOS implementation requires that your app use URLSession or any third party library that based on it.

  • We will cover the following topics:

    • How to start the SDK
    • Bot Defender integration
      • How to add the SDK’s HTTP headers to your URL requests.
      • How to handle the blocked request.
      • How to present a challenge to the user.
      • How to set custom parameters (optional).
    • Account Defender integration
      • How to enable it.
      • How to notify HUMAN’s backend on outgoing URL requests from the app.
      • How to set additional data (optional).

Important notice about iOS

The SDK uses a custom URL protocol in order to manipulate your URL requests. The SDK creates a new URLSession object to load your URL requests. As a result, there are few limitations that you should be aware of before the integration:

  1. If your implement the urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping @Sendable (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) in your URLSessionDelegate, then this function will not be called and the default OS logic will apply in your URL request.
  2. The SDK’s URLSession object is configured with URLSessionConfiguration.default. Any custom configuration on your side will not apply
  3. The SDK does not support caching in your URL requests.

How to start the SDK

  • The most important thing is to start the SDK as soon as possible in your app flow. The reason is that when your app will send an URL request to your server before the SDK was started, then the request will not include the SDK’s HTTP headers. As a result, HUMAN’s Enforcer could block the request and the SDK will not be able to present a challenge to the user.
    The best place to start the SDK is in the:
    • Application’s onCreate function on Android.
    • AppDelegate’s didFinishLaunchingWithOptions function on iOS.
  • You should start the SDK on the main thread.
  • The SDK is intercepting URL requests from your app. Your app should tell the SDK which domains are intercepted. Not specifying domains means that ALL domains will be intercepted. The SDK checks if the URL’s domain ends with one of the domains that were set. For example: If you set example.com the SDK will also intercept calls to www.example.com and api.example.com.

Here is an example of how it should be:

Android

1import android.app.Application
2import com.humansecurity.mobile_sdk.HumanSecurity
3import com.humansecurity.mobile_sdk.main.policy.HSPolicy
4import com.humansecurity.mobile_sdk.main.policy.HSAutomaticInterceptorType
5
6class MainApplication: Application() {
7
8 override fun onCreate() {
9 super.onCreate()
10 startHumanSDK()
11 }
12
13 private fun startHumanSDK() {
14 try {
15 val policy = HSPolicy()
16 policy.automaticInterceptorPolicy.interceptorType = HSAutomaticInterceptorType.INTERCEPT
17 policy.automaticInterceptorPolicy.setInterceptedDomains(setOf("example.com"), "<APP_ID>")
18
19 HumanSecurity.start(this, "<APP_ID>", policy)
20 }
21 catch (exception: Exception) {
22 println("Exception: ${exception.message}")
23 }
24 }
25}

iOS

1import UIKit
2import HUMAN
3
4@main
5class AppDelegate: UIResponder, UIApplicationDelegate {
6
7 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
8 startHumanSDK()
9 return true
10 }
11
12 func startHumanSDK() {
13 do {
14 let policy = HSPolicy()
15 policy.automaticInterceptorPolicy.interceptorType = .intercept
16 policy.automaticInterceptorPolicy.set(interceptedDomains: ["example.com"], forAppId: "<APP_ID>")
17
18 try HumanSecurity.start(appId: "<APP_ID>", policy: policy)
19 }
20 catch {
21 print("Error: \(error)")
22 }
23 }
24}

Let’s talk about what we have in the code here:

  1. We about to start the SDK as soon as possible and on the main thread.
  2. We create a HSPolicy instance. This object is used to configure the SDK’s behavior. Here, we set the HSAutomaticInterceptorPolicy/interceptorType property to HSAutomaticInterceptorType/intercept. This will turn on the Automatic Interception feature of the SDK. In short, this feature allows the SDK to manipulate URL requests and handle their responses by itself. We also set our server’s domain. This will tell the SDK to intercept URL requests only for this domain.
  3. We call the HumanSecurity/start(appId:policy:) function of the SDK. We provide the following parameters:
    • The Application instance (Android only).
    • Your AppID.
    • The policy object that we configured.

In iOS, The Automatic Interception uses the URLSessionConfiguration.default to send your URL request. However, if your app uses a custom configuration, you should set your configuration in the policy - HSAutomaticInterceptorPolicy/urlSessionConfiguration.

If your app communicates with several servers that have different AppID, you can call the HumanSecurity/start(appIds:policy:) function which allow you to pass an array of AppIDs. You should specify the relevant AppID for each API call in the SDK.

Bot Defender integration

How to add the SDK’s HTTP headers to your URL requests and handle the blocked request

  • The SDK adds its HTTP headers to you URL requests automatically. There is no need to manually add those headers.

  • The SDK handles the blocked request and present a challenge to the user automatically.

  • The SDK provides a custom error response directly to your request handler.

Here is an example of how it should be:

Android

1import com.humansecurity.mobile_sdk.HumanSecurity
2import com.humansecurity.mobile_sdk.main.HSBotDefenderErrorType
3import com.humansecurity.mobile_sdk.main.HSInterceptor
4import okhttp3.OkHttpClient
5import okhttp3.Request
6
7class MyHttpClient {
8
9 private val okHttpClient: OkHttpClient = OkHttpClient.Builder()
10 .addInterceptor(HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
11 .build()
12
13 fun sendRequest(url: String) {
14 try {
15 val request: Request = Request.Builder().url(url).build()
16 okHttpClient.newCall(request).execute().use { response ->
17 if (!response.isSuccessful) {
18 response.body?.string()?.let { responseBody ->
19 when (HumanSecurity.BD.errorType(responseBody)) {
20 HSBotDefenderErrorType.REQUEST_WAS_BLOCKED -> {
21 println("Request was blocked")
22 }
23 else -> {
24 println("Unknown error")
25 }
26 }
27 }
28 }
29 }
30 }
31 catch (exception: Exception) {
32 println("Request was failed. Exception: $exception")
33 }
34 }
35}

iOS

Using URLSession:

1import HUMAN
2
3class MyHttpClient {
4
5 func sendUrlRequest(url: URL) {
6 var request = URLRequest(url: url)
7
8 // Config your request...
9
10 let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
11 if let error {
12 let errorType = HumanSecurity.BD.errorType(error: error)
13 switch errorType {
14 case .requestWasBlocked:
15 print("Request was blocked")
16 default:
17 break
18 }
19 }
20 }
21 dataTask.resume()
22 }
23}

Using Alamofire:

Swift
1import Alamofire
2import HUMAN
3
4class MyHttpClient {
5
6 func sendUrlRequest(url: URL) {
7 AF.request(url).response { response in
8 if let error = response.error?.underlyingError {
9 let errorType = HumanSecurity.BD.errorType(error: error)
10 switch errorType {
11 case .requestWasBlocked:
12 print("Request was blocked")
13 default:
14 break
15 }
16 }
17 }
18 }
19}

Let’s talk about what we have in the code here:

  1. [Android only] We configure the HTTP client to have the HSInterceptor. This interceptor must be the last interceptor in the list.
  2. We send the URL request.
  3. We check with the SDK if the error that was received is a “blocked request error”.

Please note that while your request handler is called, the SDK is presenting a challenge to the user.

What should I do when a request is blocked

  • Handle it as a failure.

    Your app should handle the blocked request as a failure. However, you should consider that your app’s UI will be shown again after the challenge was solved/cancelled by the user. If the request was triggered by a user’s action, you should make it clear that the user may try again the same action.

How to set custom parameters (optional)

You can set custom parameters in order to configure HUMAN’s backend with additional parameters.

Those parameters can be set with a dictionary (iOS) or an hash map (Android), with the key “custom_param[x]” where [x] is a number between 1-10.

You should call the HSBotDefender/setCustomParameters(parameters:forAppId:) only after the HumanSecurity/start(appId:policy:) function was already called.

Here is an example of how it should be:

Android

1import com.humansecurity.mobile_sdk.HumanSecurity
2
3fun setCustomParametersForBotDefender() {
4 try {
5 val customParameters = HashMap<String, String>()
6 customParameters["custom_param1"] = "hello"
7 customParameters["custom_param2"] = "world"
8 HumanSecurity.BD.setCustomParameters(customParameters, "<APP_ID>")
9 }
10 catch (exception: Exception) {
11 println("Exception: ${exception.message}")
12 }
13}

iOS

1import HUMAN
2
3func setCustomParametersForBotDefender() {
4 do {
5 var customParameters = [String: String]()
6 customParameters["custom_param1"] = "hello"
7 customParameters["custom_param2"] = "world"
8 try HumanSecurity.BD.setCustomParameters(parameters: customParameters, forAppId: "<APP_ID>")
9 }
10 catch {
11 print("Error: \(error)")
12 }
13}

Account Defender integration

How to enable Account Defender in your app?

In order to enable Account Defender, you should set the UserID of your current logged-in user in the SDK.

Here is an example of how it should be:

Android

1import com.humansecurity.mobile_sdk.HumanSecurity
2
3fun onUserLoggedIn(userID: String) {
4 try {
5 HumanSecurity.AD.setUserId(userID, "<APP_ID>")
6 }
7 catch (exception: Exception) {
8 println("Exception: ${exception.message}")
9 }
10}

iOS

1import HUMAN
2
3func onUserLoggedIn(userID: String) {
4 do {
5 try HumanSecurity.AD.setUserId(userId: userID, forAppId: "<APP_ID>")
6 }
7 catch {
8 print("Error: \(error)")
9 }
10}

How to notify HUMAN’s backend on outgoing URL requests from the app

In order to allow Account Defender protect the user’s account, your app has to provide the SDK with outgoing URL requests.

While the SDK’s interceptor is enabled, the SDK is collecting your outgoing URL requests automatically. There is no need to manually call the SDK’s API.

How to set additional data (optional)

You can set additional data in order to configure HUMAN’s backend with additional parameters.

Those parameters can be set with a dictionary (iOS) or an hash map (Android).

You should call the HSAccountDefender/setAdditionalData(parameters:forAppId:) only after the HumanSecurity/start(appId:policy:) function was already called.

Here is an example of how it should be:

Android

1import com.humansecurity.mobile_sdk.HumanSecurity
2
3fun setAdditionalDataForAccountDefender() {
4 try {
5 val additionalData = HashMap<String, String>()
6 additionalData["my_key1"] = "hello"
7 additionalData["my_key2"] = "world"
8 HumanSecurity.AD.setAdditionalData(additionalData, "<APP_ID>")
9 }
10 catch (exception: Exception) {
11 println("Exception: ${exception.message}")
12 }
13}

iOS

1import HUMAN
2
3func setAdditionalDataForAccountDefender() {
4 do {
5 var additionalData = [String: String]()
6 additionalData["my_key1"] = "hello"
7 additionalData["my_key2"] = "world"
8 try HumanSecurity.AD.setAdditionalData(parameters: additionalData, forAppId: "<APP_ID>")
9 }
10 catch {
11 print("Error: \(error)")
12 }
13}