Native - Advanced Functionality
Native - Advanced Functionality
Integrating the SDK into Your Native iOS/Android App
Introduction
In this article, we will learn how to integrate the SDK into your native iOS or Android app.
Highlights
- Handle Blocked Requests with Challenge Results:
- Benefits:
- Great for analytics, logs, etc.
- Enables sending the URL request again.
- Benefits:
- Automatic Retry Option:
- Option to retry the blocked request automatically after the challenge is solved.
- URL Request Interception:
- The SDK intercepts your URL requests.
Notes:
- Android: Requires your app to use OkHttp which supports Interceptors.
- iOS: Requires your app to use
URLSessionor any third-party library based on it.
Topics Covered
- How to Start the SDK
- Bot Defender Integration
- Adding SDK’s HTTP headers to your URL requests
- Presenting a challenge to the user
- Handling the challenge’s result
- Setting custom parameters (optional)
- Account Defender Integration
- Enabling Account Defender
- Notifying HUMAN’s backend on outgoing URL requests
- Setting additional data (optional)
How to Start the SDK
- Initialize Early: Start the SDK as soon as possible in your app’s lifecycle to ensure all URL requests include the SDK’s HTTP headers. Delaying SDK initialization may result in requests being blocked by HUMAN’s Enforcer.
- Android: Initialize in the
Application’sonCreatemethod. - iOS: Initialize in the
AppDelegate’sdidFinishLaunchingWithOptionsmethod.
- Android: Initialize in the
- Main Thread: Start the SDK on the main thread.
- Domain Specification: Specify which domains the SDK should intercept. If no domains are specified, all domains will be intercepted. The SDK checks if the URL’s domain ends with one of the specified domains (e.g., setting
example.comwill also interceptwww.example.comandapi.example.com).
Example Implementation
Android
Kotlin:
Java:
iOS
Swift:
Objective-C:
Important: Don’t forget to replace <APP_ID> with your actual AppID.
Explanation of the Code
- Initialization: Start the SDK as early as possible on the main thread to ensure all URL requests include the necessary HTTP headers.
- Policy Configuration: Create an
HSPolicyinstance to configure the SDK’s behavior. Set theautomaticInterceptorPolicy.interceptorTypetoINTERCEPT_WITH_DELAYED_RESPONSEorINTERCEPT_AND_RETRY_REQUESTto enable the Automatic Interception feature of the SDK. Also, specify the domains your app will interact with. - Starting the SDK: Call the
HumanSecurity.start(appId:policy:)function with the application instance (Android only), your AppID, and the configured policy.
Notes:
- iOS: The Automatic Interception uses
URLSessionConfiguration.default. If your app uses a custom configuration, set it in the policy usingHSAutomaticInterceptorPolicy.urlSessionConfiguration. - Multiple AppIDs: If your app communicates with multiple servers having different AppIDs, use the
HumanSecurity.start(appIds:policy:)function to pass an array of AppIDs and specify the relevant AppID for each API call.
Bot Defender Integration
How to Add SDK’s HTTP Headers to Your URL Requests and Handle Blocked Requests
- Automatic Header Addition: The SDK adds its HTTP headers to your URL requests automatically. It is essential that these HTTP headers are included in every URL request.
- No Caching of Headers: Do not cache these HTTP headers as they contain a token with an expiration date. The SDK manages this token to ensure it is always up-to-date.
- Automatic Handling of Blocked Requests: The SDK handles blocked requests and presents a challenge to the user automatically.
- Custom Error Responses: The SDK provides a custom error response directly to your request handler after the challenge is solved or canceled.
- Disable Request Timeout:
- iOS: Set the request timeout to
0or configureHSAutomaticInterceptorPolicy.urlSessionRequestTimeoutto your desired timeout. - Android: Set the call/request timeout to
0(which is also the default value) and configure connectTimeout and read/write timeout as needed.
- iOS: Set the request timeout to
Example Implementation
Android
In this example, we assume your app uses OkHttp or Ktor. We recommend creating a custom Interceptor for this task. However, you may use any HTTP client of your choice and implement the same logic.
Kotlin (OkHttp):
Kotlin (Ktor):
Java:
iOS
Using URLSession:
Swift:
Objective-C:
Using Alamofire:
Swift:
Explanation of the Code
- Disable Request Timeout:
- iOS: Set
request.timeoutIntervalto0or configureHSAutomaticInterceptorPolicy.urlSessionRequestTimeoutto your desired timeout. - Android: Set the call/request timeout to
0(default value) and configureconnectTimeoutandread/write timeoutas needed.
- iOS: Set
- Adding HTTP Headers:
- The SDK automatically adds its HTTP headers to your URL requests via the
HSInterceptor. Ensure that this interceptor is the last in the interceptor chain.
- The SDK automatically adds its HTTP headers to your URL requests via the
- Sending the Request:
- Execute the URL request using your configured HTTP client.
- Handling the Response:
- The SDK provides a custom error response after the challenge is solved or canceled. Check the error type to determine the challenge result (
CHALLENGE_WAS_SOLVEDorCHALLENGE_WAS_CANCELLED). - Note: When
HSAutomaticInterceptorTypeis set toINTERCEPT_AND_RETRY_REQUEST, the SDK will resend the blocked request after the challenge is solved. However, the second request could still be blocked, and the SDK won’t resend it again.
- The SDK provides a custom error response after the challenge is solved or canceled. Check the error type to determine the challenge result (
Important: Handle the challenge result appropriately, considering scenarios where the challenge is canceled or the retry attempt fails.
Challenge outcome: solvedWithError / SOLVED_WITH_ERROR
solvedWithError (iOS) / SOLVED_WITH_ERROR (Android) means the user completed
the challenge, but the SDK could not confirm the pass. Typical causes are a
post-challenge Collector refresh that failed or timed out, or session
initialization that never completed. The pass could not be confirmed.
It is not a failed challenge and not a cancelled challenge. The user did the work.
Because the pass could not be confirmed, the next protected request may be blocked again. Surface a connectivity message rather than retrying silently in a loop.
A cancellation reason never changes the cancelled / CANCELLED result and
must not be read as a successful pass. It remains useful for telling a
user-initiated dismissal apart from a load failure.
What is called where
Delegates and detailed/reason APIs still receive solvedWithError /
SOLVED_WITH_ERROR. In 5.x the legacy single-argument handleBlockResponse
callback folds to solved / SOLVED. Delayed interceptor bodies fold to
challengeWasSolved / CHALLENGE_WAS_SOLVED; non-delayed intercept returns
requestWasBlocked / REQUEST_WAS_BLOCKED. Use detailedCallback (iOS) or
handleBlockResponseWithReason (Android) for the detailed outcome.
You will receive two delegate calls
When solvedWithError / SOLVED_WITH_ERROR occurs and you have implemented
botDefenderChallengeSolvedWithError, the SDK calls it and
then also calls botDefenderChallengeSolved. iOS delegate methods are
non-throwing and both calls are issued sequentially. On Android both callbacks
run inside one try block, so a throwing solved-with-error implementation
skips the legacy callback.
This is one challenge, not two. Do not count two passes and do not trigger two retries.
Back press (Android only)
Dismissing the challenge with the hardware back button produces CANCELLED
with the reason USER_DISMISSED_BACK_PRESS. It never produces
SOLVED_WITH_ERROR.
This reason is Android only. iOS has no equivalent event.
Kotlin coroutine callers (Android only)
The suspend overload of handleBlockResponse returns the result without the
reason. If you need the reason, use handleBlockResponseWithReason.
Existing delegate implementations (Android only)
Android botDefenderChallengeSolvedWithError has a default no-op
implementation, so delegates written before 5.1.0 continue to compile and behave
as before. iOS exposes the same method as an optional protocol requirement.
Known limitation
SOLVED_WITH_ERROR was added to an existing result enum in a minor release. As a
result, an exhaustive when written against 5.0 may now require a new case.
This cannot be corrected within the 5.x line without breaking one group of
integrations. It is addressed in the next major version.
What to Do When a Request Is Blocked
- Handle as a Failure:
- Treat blocked requests as failures. After the challenge is solved, you may resend the request.
- If the request was triggered by a user’s action, inform the user that they can retry the same action.
- Use Handler Callback for Analytics:
- Utilize the handler callback to log analytics, create logs, etc.
- Optional Request Retry:
- You may use the handler callback to retry the original request when appropriate. Consider the following:
- Callback Scope: The callback is called outside the original request’s scope. Ensure your app handles this correctly.
- Challenge Cancellation: If the challenge is canceled by the user, do not retry the request to avoid it being blocked again.
- Retry Block Possibility: The retry attempt may also be blocked. Do not assume it will succeed.
- You may use the handler callback to retry the original request when appropriate. Consider the following:
Understanding the Block Response
-
Enforcer Decision:
- When HUMAN’s Enforcer decides to block a request, it returns a JSON string in the response body with an HTTP status code of
403. Example response:
Note: This JSON contains metadata for the SDK.
- When HUMAN’s Enforcer decides to block a request, it returns a JSON string in the response body with an HTTP status code of
-
Passing Response to SDK:
- Your app should pass the entire JSON response to the SDK via the
HSBotDefender/handleBlockResponsefunction. If not, the SDK won’t present a challenge to the user.
- Your app should pass the entire JSON response to the SDK via the
Setting Custom Parameters for Bot Defender (Optional)
You can configure HUMAN’s backend with additional parameters by setting custom parameters.
- Android: Use a
HashMap<String, String>. - iOS: Use a
Dictionary<String, String>.
Key Format: Use keys in the format custom_param[x], where [x] is a number between 1-10.
Important: Call the HSBotDefender.setCustomParameters(parameters:forAppId:) function only after the HumanSecurity.start(appId:policy:) function has been called.
Example Implementation
Android
Kotlin:
Java:
iOS
Swift:
Objective-C:
Account Defender Integration
How to Enable Account Defender in Your App
To enable Account Defender, set the UserID of the currently logged-in user in the SDK.
Example Implementation
Android
Kotlin:
Java:
iOS
Swift:
Objective-C:
How to Notify HUMAN’s Backend on Outgoing URL Requests from the App
To enable Account Defender to protect the user’s account, your app must provide the SDK with outgoing URL requests.
Note: While the SDK’s interceptor is enabled, the SDK automatically collects your outgoing URL requests. No manual API calls are required.
Android
In this example, we assume your app uses OkHttp or Ktor. We recommend creating a custom Interceptor for this task. However, you may use any HTTP client of your choice and implement the same logic.
Kotlin:
Kotlin (OkHttp):
Kotlin (Ktor):
Java:
iOS
Swift:
Objective-C:
Setting Additional Data for Account Defender (Optional)
You can configure HUMAN’s backend with additional parameters by setting additional data.
- Android: Use a
HashMap<String, String>. - iOS: Use a
Dictionary<String, String>.
Important: Call the HSAccountDefender.setAdditionalData(parameters:forAppId:) function only after the HumanSecurity.start(appId:policy:) function has been called.
Example Implementation
Android
Kotlin:
Java:
iOS
Swift:
Objective-C: