iOS Integration

Overview

This document elaborates on the integration steps of the EdgeOne client attestation SDK in an iOS project, including SDK support for importing, permission configuration, initialization, engine startup, challenge handling, and token usage in API requests.

Integration Steps

Note:
Before starting integration, ensure you have read and understood the Mobile Terminal Integration Overview to learn about the basic attestation process on mobile.

1. Adding EdgeOne SDK to Your Project

Integrating the EdgeOne client attestation SDK into your iOS project is the first step. You can introduce the SDK through CocoaPods. Add the following content to your Podfile:
pod 'ClientAttestation', :podspec => './SDK'
Then run the following command:
pod install

2. Configuring Info.Plist Permission

The SDK requires basic network access during the attestation process. Please add the following permission declaration in your project's Info.plist file to ensure the SDK can perform normal network communication:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
If your application needs to access the Internet, please ensure this permission is declared.
<key>NSInternetPermission</key>
<true/>
Note: The NSAllowsArbitraryLoads setting allows application loading of non-HTTPS resources. In a production environment, strongly recommend configuring ATS exceptions to only allow necessary domains via HTTPS to enhance security.

3. Initializing the SDK

Before using any attestation feature, you need to initialize the EdgeOne SDK with your service domain and optional log level. This operation is typically executed once in your AppDelegate or at application startup.
import ClientAttestation

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// SDK initialization
let baseUrl = "www.example.com" // set to business domain
let basOptions = TCBasOptions()
basOptions.baseUrl = baseUrl
basOptions.logLevel = LOG_LEVEL_DEBUG // Optional, set log level
TCBas.initialize(with: basOptions)
return true
}
Parameter description:
baseUrl: Your EdgeOne service domain name, such as www.example.com.
logLevel: Optional parameter used to control the SDK log output level. Optional values include:
LOG_LEVEL_NONE: Disable logs (default)
LOG_LEVEL_DEBUG: Enable logs at debug level and above
LOG_LEVEL_INFO: Enable logs at info level and above
LOG_LEVEL_WARN: Enable logs at warning level and above
LOG_LEVEL_ERROR: Enable logs at error level and above

4. Starting the Attestation Engine

After the SDK initialization is completed, you need to start the client attestation engine so that the SDK can begin acquisition and manage attestation tokens. This operation starts the necessary background process inside the SDK.
// Start the client attestation engine
[[ClientAttestation sharedInstance] start];
Note: After the attestation engine starts, the SDK will be ready to handle attestation challenges and manage attestation tokens.

5. Execute Client Attestation Challenge

The attestation challenge is a key step to obtain the attestation token. This process involves retrieving the challenge ID and passing it into the SDK. The SDK will display the necessary UI (such as showing the Captcha in WKWebView) as needed and compute the attestation token. This is done via the attestWithParams() method provided by the SDK.
// attestId
// Get from console when actively initiating a challenge
// Retrieve from the 'EO-Attest-Challenge' header field in the http response when passively triggering a Challenge
NSString *attestId = @"your-attestId";
AttestParams *params = [[AttestParams alloc] init];
params.attestId = attestId;
params.webView = webView; // WebView used for Captcha display
params.reqTimeoutMillis = 60000; // Optional, request timeout
[[ClientAttestation sharedInstance] attestWithParams:params
callback:self];

// Implement the AttestCallbackDelegate protocol
#pragma mark - AttestCallbackDelegate
- (void)onSuccess:(NSString *)token {
// Return the risk invoice, place the invoice in the header field 'EO-Attest-Token' of the http request
}

- (void)onError:(NSError *)error {
// Error message returned
}
Parameter description:
attestId: Configure the challenge ID, get from console or return in request result.
webView: optional parameter, a WKWebView instance. When the authenticator requires user interaction (such as Captcha), you must provide this parameter. If UI interaction is not required, the WKWebView can be hidden.
reqTimeoutMillis: Optional parameter to set request timeout in milliseconds. Default is 60 seconds.

6. Include an Attestation Token in API Request

When your iOS app initiates an API request to a backend service protected by EdgeOne, must include an attestation token in the request header. You can call the getAttestationToken() method provided by the SDK to readily obtain the current valid attestation token.
Note:
After each successful call to attestWithParams(), the SDK generates or updates the attestation token. Before attaching the token to request headers, be sure to call getAttestationToken() again to get the latest token. Each time you need to use token data, please retrieve new token data. Do not save or reuse the token data returned by getAttestationToken().
// Get client attestation invoice
NSString *attestToken = [[ClientAttestation sharedInstance] getAttestationToken];

// Example: Add the token to your network request header
// Assuming you are using URLSession or another network library
if (attestToken) {
// Your request object
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://your-backend-api.com/data"]];
[request setValue:attestToken forHTTPHeaderField:@"EO-Attest-Token"];
// Continue sending the request
}
Note: Ensure this token is included in each API request requiring attestation. The SDK will automatically manage the token lifecycle. You just need to get the latest token before sending a request.

7. Handling Server Response and Challenges

When your backend service (protected by EdgeOne) receives a client request, it checks if the request contains a valid attestation token. If attestation is required but no valid token is provided, the server will return HTTP status code 428, indicating the client needs additional attestation. This is a key link in iOS client integration that requires proactive adaptation by developers.
Your iOS application needs to implement a mechanism to capture and handle these HTTP 428 responses. For the detailed process, please refer to reobtaining the attestation token or renewing an expired attestation token (handling HTTP 428 challenges).
Here is a simplified example of handling HTTP 428 challenges:
// Assume your network request processing logic
- (void)sendAPIRequest:(NSMutableURLRequest *)request {
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"network error: %@", error.localizedDescription);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 428) {
// Received 428 challenge, extract challenge ID
NSString *challengeId = httpResponse.allHeaderFields[@"EO-Attest-Challenge"];
if (challengeId) {
NSLog(@"Received 428 challenge, challenge ID: %@", challengeId);
// Execute attestation challenge
// Create or reuse a WKWebView instance as needed
WKWebView *webView = [[WKWebView alloc] init];
AttestParams *attestParams = [[AttestParams alloc] init];
attestParams.attestId = challengeId;
attestParams.webView = webView;
[[ClientAttestation sharedInstance] attestWithParams:attestParams callback:self];
// Note: Need to process the AttestCallbackDelegate callback and resend the request in onSuccess
} else {
NSLog(@"428 EO-Attest-Challenge header not found in response");
}
} else if (httpResponse.statusCode == 200) {
NSLog(@"Request succeeded.");
// Process business data
} else {
NSLog(@"Request failed, status code: %ld", (long)httpResponse.statusCode);
// fix other errors
}
}];
[task resume];
}

// Example call
// NSMutableURLRequest *initialRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://your-backend-api.com/protected-data"]];
// [self sendAPIRequest:initialRequest];

// Resend the request in the onSuccess method of AttestCallbackDelegate
#pragma mark - AttestCallbackDelegate
- (void)onSuccess:(NSString *)token {
NSLog(@"Challenge Success, obtain new token: %@", token);
// Resend the original request with the new token
// Need to get the previous request object and resend
// For example:
// NSMutableURLRequest *retryRequest = [self.lastFailedRequest mutableCopy]; // Assume you saved the last failed request
// [retryRequest setValue:token forHTTPHeaderField:@"EO-Attest-Token"];
// [self sendAPIRequest:retryRequest];
}

- (void)onError:(NSError *)error {
NSLog(@"attestation challenge failure: %@", error.localizedDescription);
}

8. (Optional) Using WKWebView for Interactive Attestation (And JS Attestation)

In some client attestation scenarios, the authenticator may require user interaction (e.g., interactive Captcha) or execute compute-intensive tasks (e.g., Proof of Work encryption). At this point, EdgeOne SDK requires specific runtime environment support. On mobile platforms, WKWebView (iOS platform) is the key component to implement these features.
When the authenticator needs to render an interactive CAPTCHA or run a JavaScript-based Proof-of-Work encryption challenge, the SDK requires a WKWebView instance to be provided when calling the attestWithParams() method. This means developers must allocate a WKWebView instance in advance in the application and pass it as an argument to the SDK when calling the attestation API.

Interactive Attestation Scenario

Some authenticators (such as TC-CAPTCHA using embedded or pop-up interaction settings) require a WKWebView instance to render their interactive interface. The WKWebView instance will display the CAPTCHA page within the application, so it must be preset to ensure correct display.
Embedded Interactive Attestation: The CAPTCHA interface is displayed as a fixed block on the device screen. To ensure correct UI display without affecting user experience, developers must preset the rendering window's size, layering sequence, and alignment mode. Please note, the embedded attestation GUI does not scale with the screen view. For example, TC-CAPTCHA embedded mode recommends reserving at least 300x230 pixel space to achieve the best rendering effect and user interaction experience.
Pop-up Interactive Attestation: The CAPTCHA interface appears as a floating window on the device screen when attestation is triggered. Similar to embedded attestation, the size, layering sequence, and alignment mode of the rendering window must be preset. The key feature of pop-up attestation is that when the screen view is below a specific threshold, the pop-up attestation GUI will automatically resize to adapt to different screen sizes. For example, TC-CAPTCHA pop-up mode has an initial rendering block size of 360x360 pixels.

JavaScript-Based Attestation Scenario

Some authenticators (such as TC-CAPTCHA in silent mode) require a WKWebView instance as the JavaScript runtime environment, primarily for executing encrypted Proof of Work (PoW) challenges. In this case, the WKWebView instance provides only a JavaScript execution sandbox, with no need to visibly render any UI. Therefore, the passed-in WKWebView instance does not need to be visible, and the SDK will not use it for UI rendering.