> For the complete documentation index, see [llms.txt](https://waap.docs.link11.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://waap.docs.link11.com/mobile-sdk-v2.2.x/developer-guide-sdk-v2.2.x.md).

# Developer Guide: SDK v2.2.x

## Overview <a href="#overview" id="overview"></a>

The Reblaze platform includes a proprietary Mobile SDK: a unique client certification mechanism for mobile applications. Organizations can publish their iOS and Android apps with the SDK embedded.

In use, the SDK signs the application, authenticates the device, and verifies user identity. It validates all requests coming from legitimate apps, adding a cryptographic HMAC signature to each one. The signatures are non-reproducible, non-guessable, and non-repeating.

The SDK provides a reliable and secure mechanism to confirm that the traffic is originating from a legitimate app user and not a bot or emulator. Incoming traffic that was not verified by the SDK can safely be rejected, or have other custom responses configured.

The Reblaze Mobile SDK is available to Reblaze customers. To get access to the latest version, send a message to:

[**mobile-sdk-dev@reblaze.com**](mailto:mobile-sdk-dev@reblaze.com)

## Scope

The SDK currently supports:

### **Android**:

* Java
* Kotlin

### **iOS:**

* Swift-5 (Xcode 11)
* Objective-C (Xcode 11)

The SDK package **ReblazeSDK.zip** contains example applications and libraries, as well as a Flutter plugin that works on both Android and iOS. We also include a React-Native example, which demonstrates the use of native bridges for iOS and Android.

{% hint style="warning" %}
The SDK comes with internal protections that make it harder to abuse it to attack your backend services, or backend services of other Reblaze customers. Still, the Reblaze SDK alone does not protect your application. We strongly recommend to all our customers to apply obfuscation and runtime protection techniques for their apps.
{% endhint %}

## Getting Started <a href="#getting-started" id="getting-started"></a>

First, read the platform-independent information on this page. Then go to the page for your specific platform (links are at the bottom of this page) and follow the setup instructions.

## How the SDK works <a href="#how-the-sdk-works" id="how-the-sdk-works"></a>

{% hint style="info" %}
In the discussion below, **customer** will refer to the organization who uses the Reblaze SDK, **client application** will refer to the application in which the SDK is used, and **user** will refer to the end user of the client application.
{% endhint %}

After configuration is completed and the SDK is in use, it performs several activities:

* **Signs the requests** that the client application sends over the network, to authenticate that they originated from a legitimate user of the client application.
* **Sends summaries of certain user actions** (their interactions with the client application) to Reblaze for UEBA (User and Entity Behavioral Analytics).
* **Sends (optional) custom events** to Reblaze for enhanced UEBA and reporting.

Each activity is described in detail in the [**SDK Operations**](#sdk-operations) section below.

### Setup <a href="#setup" id="setup"></a>

The minimal requirements for using the SDK are:

* [Upload the App Signature(s)](#server-side-configuration) on the Backend.
* Set the `backendUrl` property.

There are additional [properties](#sdk-properties) that can be configured, but in many cases, the default values will be adequate.

We recommend configuring the SDK by adding the `ReblazeURL` string to iOS app **Info.plist** or on Android, to **values** resource (with Flutter or React Native, you should set this string for both platforms). This guarantees that the SDK will become activated as early as possible, and will take full advantage of the [**Remote Configuration**](#remote-configuration)**.**

Additional SDK properties can be set in two ways:

* **Local configuration**: the properties are set programmatically in the client application.
* **Remote configuration**: the properties are set by the Reblaze backend web proxy.

These options are not exclusive. At a particular time, an SDK might have all its properties configured locally, while later at a different time, some of its properties might be overridden remotely.

### Local Configuration <a href="#local-configuration" id="local-configuration"></a>

To configure the SDK programmatically, we recommend overriding the `Application.onCreate()` method on Android. For iOS, the best choice would be to configure the SDK in `application:didFinishLaunchingWithOptions:` method.

The SDK's properties (except the read-only ones) can be queried or changed at any time, with a dedicated API. For example:

```
reblaze.reportCounters = ReblazeSDK_ReportCountersALL; // Objective-C
reblaze.setTokenHeaderName("session-id"); // Java
reblaze.setToken('Bearer cn389ncoiwuencr'); // Flutter
let interval = reblaze.interval // Swift
val configName = reblaze.configurationName // Kotlin
```

{% hint style="info" %}
In Java and Flutter, we use getter and setter APIs, e.g. `setToken()` or `getInterval()`. If the language allows, it's preferable to use assignment operators.
{% endhint %}

The *getter* will always give you the effective value, but the *setter* might be affected by remote configuration, as discussed next.

### **Remote Configuration** <a href="#remote-configuration" id="remote-configuration"></a>

You can setup the Reblaze backend web proxy to override local configuration settings. This is done via the Mobile SDK Profiles on the backend.

Reblaze always has one, and only one, active Mobile SDK Profile. Each Profile contains a list of zero or more property settings. Each property setting in the active Profile will be used to configure the SDK in the client application.

Properties which are not defined in the active Profile will be determined locally. **The default Profile is empty**. Therefore, when the default Profile is active, all SDK configuration is determined locally.

When a local property setting does not match the corresponding property setting in the active Profile, the Profile's setting is used. However, the local setting is not discarded. If the active Profile changes, and the new Profile no longer has a setting for that property, then the local setting will take effect.

The following diagram demonstrates this flow. It uses the `interval` parameter as an example, but the same logic works for all other parameters.

<figure><img src="https://584218395-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LuRghgerfT6t9aVOOha-1521617150%2Fuploads%2FLL9emhXGx8WDweY5H7iZ%2Fintro-flowchart.png?alt=media&amp;token=340a9d29-89ae-4432-b932-7dd91c17812d" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
This demonstrates why you should not cache the values you get from the SDK for extended periods, because the parameters may be changed at any time due to the remote configuration.
{% endhint %}

### SDK Properties <a href="#sdk-properties" id="sdk-properties"></a>

Here are all the properties available to your app:

| Property          | Description                                                                                                                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| configurationName | Name of server-side configuration (it will be an empty string if the configuration is fully client-side). *It is read-only.*                                                                                         |
| backendUrl        | <p>URL for the customer's application server.<br><br><em>The remote configuration cannot override this value.</em></p>                                                                                               |
| tokenHeaderName   | The name of the HTTP header that contains a unique token for this user or session. (**Default**: `authorization`).                                                                                                   |
| token             | The value for the header specified above (for example, the user's login token)                                                                                                                                       |
| interval          | Determines how often UEBA events are sent to the WAF, in seconds. *Minimum*: 12 sec. *Default value:* 5 min = 300 sec.                                                                                               |
| timeslice         | <p>Time interval for grouping the UEBA data, milliseconds (rounded to 100ms). <em>Default value:</em> 1 sec = 1000 ms.<br><br><em>Zero</em> <code>timeslice</code> <em>means that no grouping is performed.</em></p> |
| userAgent         | <p>The header that will appear in Console logs for the sync messages that the SDK sends to the Reblaze service. It depends on the platform.<br><br><em>The remote configuration cannot override this value.</em></p> |
| reportCounters    | Which counters will be reported, either **ALL** *(default)* or **NONE**.                                                                                                                                             |
| autoSign          | Which requests will be signed automatically, either **NONE** *(default)* or **ALL**. *Applies to iOS only.*                                                                                                          |
| hashVariant       | Which variant of hash function the client will use in this session. *In this version, this property is read-only, and fixed at **"v2".***                                                                            |

The list above is general information. The platform-specific documentation pages contain more information about setting properties.

### Backend Configuration <a href="#server-side-configuration" id="server-side-configuration"></a>

Your `backendUrl` points to your application server, protected by the Reblaze web proxy. You must configure this web proxy to recognize the *signature* of your app.

The Reblaze console contains a page (**Settings / Web Proxy**) that includes this section:

<figure><img src="https://584218395-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LuRghgerfT6t9aVOOha-1521617150%2Fuploads%2FLcxwYdEggag5PmbWhZHE%2Fintro-sdk-settings.png?alt=media&amp;token=3b28f1fb-8793-4889-8db4-2872e60ec31d" alt=""><figcaption></figcaption></figure>

**App Signatures** is a list of SHA-256 digests of recognized certificates for your client application(s).

To find the signature for an iOS app, you can open the *Apple Development Certificate* in the Keychain app, and copy the **SHA-256 fingerprint**. Alternatively, you can [extract](https://stackoverflow.com/a/14885447) this fingerprint from the **ipa** bundle.

For an Android app, you can get the SHA-256 fingerprint from the **keystore** or extract it from a signed APK with the **apksigner** tool (part of the Android SDK). See detailed instructions [here](https://security.stackexchange.com/questions/178936/how-to-verify-sha256-fingerprint-of-apk).

When uploading the fingerprint to the Reblaze Console, make sure that it contains hexadecimal characters only, in lowercase, without spaces. Any number of signatures may be 'Active' at given time.

To avoid the issue of an app getting a new signature when uploaded to the App Store or Google Play, there is a protocol between the SDK and the backend that negotiates the signature remotely and updates the system with a new one, if such was generated.

The communication between the components takes place under the /74d8-ffc3-0f63-4b3c-c5c9-5699-6d5b-3a1f endpoint, and when a new signature is introduced, it will be provided as a value for the header named "sig" (see screenshot below).

This new signature shall then be added to the app signatures list under the Mobile SDK settings in Reblaze Console.

To find it easily in the View Log, use this filter:\
&#x20;`url:/74d8-ffc3-0f63-4b3c-c5c9-5699-6d5b-3a1f` .

<figure><img src="https://584218395-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LuRghgerfT6t9aVOOha-1521617150%2Fuploads%2FTemFCSTZyKO1Vfg7vaaQ%2Fintro-request-details.png?alt=media&amp;token=9b1f7cfe-216b-492f-9c35-2329a851f67c" alt=""><figcaption></figcaption></figure>

**Profiles** is a list of remote configurations, each of which contains settings that can override the parameters of the SDK on all mobile clients. The **Default** profile is always empty, and when it is active, the SDK parameters are fully determined by the app local configuration. Only one remote profile may be active at given time. For more on this, see the discussion above on remote configuration.

**Grace period** defines the allowable time between the timestamp of a request and the time that Reblaze receives the request from the application. Requests with a longer delay will be rejected. (The grace period can be set to 24 hours to allow maximum use of the generated hash.)

**Token Header Name** determines the name of the header that contains session or user authentication token. With the new versions of Mobile SDK, it can be empty. This name should match the **tokenHeaderName** configuration parameter.

During testing, you may allow running the app on Simulator (iOS) or Android Emulator. These generate a special signature: `"abadbabe"`. Make sure that this is disabled on Production. Note that you can also use [Offline Testing](#offline-testing-mock) both on Simulator and on a physical device.

**Profile Format and Restrictions**

As shown above, the backend can override the parameters of the SDK. The active remote profile applies to all mobile clients, both Android and iOS. The profile is stored as a JSON string. Correct JSON syntax is enforced, all strings must be "quoted". But in the current version, the there is no verification that this JSON follows the scheme expected by the SDK on the app (client) side. Unexpected parameters (including wrong capitalization) will be silently ignored. The valid parameters are listed in the table below:

| Parameter      | Type and Restrictions                                                                                                                                                                 |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name           | String, required. Don't specify it in the JSON, it will be taken from the left column. The SDK will see this as **configurationName**.                                                |
| interval       | Integer, in seconds. If it is below the minimum of 12 sec, the app will use 12 sec.                                                                                                   |
| timeslice      | <p>Integer, in milliseconds. The app will round this value to hundreds of milliseconds.<br><br><em>Zero</em> <code>timeslice</code> <em>means that no grouping is performed.</em></p> |
| reportCounters | String, either **"ALL"** or **"NONE"**.                                                                                                                                               |
| autoSign       | String, either **"NONE" or "ALL"**.                                                                                                                                                   |

*The following parameters are supported, but you should have a very strong reason to change them remotely.*

| tokenHeaderName | String. It should be synchronized with the **UID Header Name** setting of the Web Proxy, and also the app must comply with this change.                                   |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hashVariant     | String, should be **"v2"**. Otherwise, the SDK will not be able to communicate with the backend anymore, and all future app requests will not be recognized as **Human**. |

As long as a parameter is specified in the active profile, its value will override whatever is specified in the application code, but a different active profile may be chosen at any moment, or the same active profile may be edited.

When the changed profile does not specify some parameter anymore, the *local* value actualizes. Note that the remote configuration does not persist when the application shuts down.

## SDK Operations <a href="#sdk-operations" id="sdk-operations"></a>

### Signing the Network Requests <a href="#signing-the-network-requests" id="signing-the-network-requests"></a>

The SDK provides a way to sign the Web requests that the app sends to the customer's microservice/API endpoint. The signatures are non-reproducible, non-guessable, and non-repeating. They provide a reliable, secure mechanism to verify that the packets are originating from the legitimate app that is operated by a user, and not from an emulator or other bot.

The SDK introduces an additional HTTP header (**`reblaze.reblazeHeader`**) that should be present in all HTTPS requests that go through the Reblaze WAF. Depending on your network configuration, this may involve different URL domains and paths.

{% hint style="info" %}
The name of the header, **`rbzsdk`**, is reserved. The SDK may also inject predefined **`rbzsdk`**&#x61;n&#x64;**`rbzsdk_token`**&#x63;ookies.

This header and cookies are not forwarded by Reblaze to the customer's backend.
{% endhint %}

The signature is returned by the `generateHash()`method, and can be valid for up to 24 hours:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
httpsURLConnection.setRequestProperty(reblaze.reblazeHeader, reblaze.generateHash())
```

{% endtab %}

{% tab title="Java" %}

```java
httpsURLConnection.setRequestProperty(reblaze.reblazeHeader, reblaze.generateHash());
```

{% endtab %}

{% tab title="Swift" %}

```swift
urlRequest.setValue(reblaze.generateHash() forHTTPHeaderField: reblaze.reblazeHeader)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[nsMutableURLRequest setValue:[reblaze generateHash] forHTTPHeaderField:reblaze.reblazeHeader];
```

{% endtab %}

{% tab title="Flutter" %}

```dart
final response = await client.get(uri),
    headers: {
      HttpHeaders.authorizationHeader: token, // same as reblaze.setToken()
      reblaze.reblazeHeader: await reblaze.generateHash(),
    }
);
```

{% endtab %}
{% endtabs %}

This method relies on the system clock, on the app identity, device identity and, optionally, on a user session token (see below). To verify the *app identity*, the app signature (the SHA-256 digest of the developer's certificate) will be registered with the Reblaze WAF, as discussed above. The *device identity* does not compromise the user's privacy. Obtaining this id requires no permissions on either iOS or on Android. It cannot be used to recognize that different apps are running on the same device. Also, it will be reset if an end-user reinstalls the app (but it survives the normal app upgrade).

**Protected User HTTP Session**

If your API features an HTTP session that is specified by a header that holds some kind of user login token, or persistent user id, you can use the Reblaze SDK to keep track of this session and provide protection from user id spoofing and token hijacking. The SDK secure hash will involve this token or id, so that the WAF rules can safely track the session, and make sure that the token is not manipulated by a man-in-the-middle or similar attack.

Perhaps you don't have such an id when the app starts up (before the user completes a signup or login process). Reblaze will enforce login-time security rulesets while this value is not available. Make sure that you set this property as soon as you know it, for the better protection.

Reblaze can use this token to enforce per-user security rulesets such as dynamic rate limits. This token can also help you to observe the activities of individual users within the traffic logs on the Reblaze console.

This support is optional, and may be turned off at any time. Simply set **reblaze.token** to an empty string.

**Auto-signing and WebView**

WebViews embedded in your mobile app are powerful browsers on their own, and their communications are fully protected by the Reblaze WAAP, which monitors end-user activity and filters bot traffic. However, this protection relies on Javascript, which should be disabled on WebView as the best practice recommended by OWASP. Without Javascript, the traffic must be protected by this Mobile SDK.

You can pass the **rbzsdk** header with a request that returns HTML that you load into a WebView, but this approach does not support the links and resources (including AJAX) that are parts of that HTML. To handle these use cases, the Mobile SDK introduces *auto-signing*. The details of this approach will be described separately on [Android](/mobile-sdk-v2.2.x/android.md) and [iOS](/mobile-sdk-v2.2.x/ios.md), but the basic idea is the same: the SDK automatically signs all relevant requests as long as the application needs this. While debugging the application, all auto-signed requests will be reported to the listener (see [Monitoring the SDK](#monitoring-the-sdk)).

### Sending Biometric Summaries <a href="#sending-biometric-summaries" id="sending-biometric-summaries"></a>

The SDK will periodically send summaries of user events to Reblaze. These are generated automatically based on the user's interaction with the client application. The SDK accumulates the information and sends it to Reblaze at an interval set in the SDK configuration. Each summary is signed by the SDK, to prevent rogue interceptors from editing the reports.

This information is used to build behavioral profiles, which are used to recognize legitimate usage patterns for the client application. These profiles provide an additional layer of security, based on private analytics and cumulative user-event data to which threat actors have no access. Thus, they provides an additional form of client authentication that is extremely difficult for threat actors to defeat.

The summary may include counts of the following user behavior events:

`tap, click, gesture, keyDown, keyPress, keyUp, touchDown, touchMove, touchUp, timeInBackground, deviceOrientation`

{% hint style="info" %}
The latter refers to device orientation *changes*; some of these happen when the app starts, without really rotating the device. On the other hand, if the user chooses fixed device orientation, some device rotations will not be counted.
{% endhint %}

In the current version of the SDK, you can use `ALL` to choose all standard counters (this is the default), or `NONE`. The standard counters include also the count of `signedRequests` (this counter may help to check that the SDK is not being abused) and a timestamp (of the first event that is counted in the batch).

The summary also includes the current battery level, charging mode, application mode (foreground or background), and device mode (e.g. emulator).

Reblaze includes these reports in its console. They can be observed by using this [filter](https://gb.docs.reblaze.com/v/v2.16/using-the-product/best-practices/reblaze-filter): `url:/8d47`.

As mentioned above, Reblaze uses the event counters to build behavioral profiles for users of the client application. After an initial learning period, Reblaze will understand how legitimate users interact with the application. Subsequent users who do not conform to these behavioral patterns can be flagged as suspicious and/or **blocked from access to the API endpoint.**

**Transmission Interval**

The summary will be sent in a form of signed JSON to the Reblaze server at the specified pace. The summary is not sent if there is nothing to report, e.g. if the application is in background, and does not communicate with the background. The interval cannot be shorter than `MINIMUM_INTERVAL` (12 sec). The default interval `DEFAULT_INTERVAL` is 5 minutes. Tune your interval according to the application usage patterns; for best performance, there should be a few reports sent during a user session. The event counts may be grouped in time slices, according to the `timeslice` parameter.

### Reporting Custom Events <a href="#reporting-custom-events" id="reporting-custom-events"></a>

In addition to standard events, the SDK can also accumulate custom events, as reported by the client application. Each custom event is identified with a string chosen by the customer. Customers can define as many types of events as they wish, like this:

```
reblaze.sendEvent("buttonPressed")
```

Sending more types of events has the following benefits:

* **Reblaze can construct more sophisticated behavioral profiles**, and thus can enforce more robust security policies. **Example:** a mobile API endpoint is receiving numerous requests for data from a specific IP address. Those requests for data are usually generated by a user interacting with the customer's application in a certain way. If the customer has coded the application so that all these interactive events are sent to Reblaze, then Reblaze will have learned that these types of data requests should be accompanied by these specific custom events. A high number of data requests that are *not* accompanied by these event notifications would indicate that this is not a legitimate user; instead, it is probably an attacker using an emulator.
* **Reblaze includes all the custom events in its traffic logs.** Thus, customers can view fuller records of all the events being generated in each session.

### Monitoring the SDK <a href="#monitoring-the-sdk" id="monitoring-the-sdk"></a>

The SDK does all its work in the background, and does not require application awareness of its state. It will not throw exceptions, display error logs, or crash your app.

However, we provide a way for the app to be aware of SDK status. For all SDK properties that are set by the app, or overridden by remote configuration, an *SDK Event* *Listener* can be used to keep track of networking errors that happen while the SDK is running:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
reblaze.setEventListener { kind, message ->
  val text: String
  if (kind == Kind.ERROR) {
    Toast.makeText(context, message, Toast.LENGTH_LONG).show()
  }
  Log.println(kind.value, "reblaze", message)
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
reblaze.setEventListener() { kind, message in
  guard kind.rawValue >= reblaze.Kind.INFO.rawValue else { return }
  print("reblaze:", kind, message)
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
    [reblaze setEventListener: 
        ^(ReblazeSDK_Kind kind, NSString * _Nonnull message) {
        NSLog(@"reblaze: %s %@", ReblazeSDK_KindName[kind], message);
    }];
```

{% endtab %}

{% tab title="Java" %}

```java
reblaze.setEventListener(new SdkEventListener() {
  @Override
  public void onSdkEvent(Kind kind, String message) {
    if (kind.getValue() >= Log.WARN)
      Log.println(kind.getValue(), "reblaze:", message);
  }
});
```

{% endtab %}
{% endtabs %}

Setting the SDK event listener does not depend on initialization. Actually, you may prefer to have monitoring ready when the SDK sends its first handshake HTTPS request to the backend. Therefore, we recommend to define the listener in the **Application** class. Note that on Android, the SDK does not retain the listener (it uses a weak reference), so it's your responsibility to protect it from being destroyed by the garbage collector.

For convenience of working with the **Log.println()**, the values of **Kind** enum match those of the Android framework **Log** class.

{% hint style="warning" %}
EventListener cannot be set in Flutter or ReactNative, due to performance limitations of these frameworks. You can add custom event listeners in the platform-dependent code of your app.
{% endhint %}

### Offline Testing (Mock) <a href="#offline-testing-mock" id="offline-testing-mock"></a>

The SDK will not work when the device is not connected to the internet and the Reblaze server is not set up. But you can test how your app will work with the SDK without any server, even offline. To perform offline tests, use `enableMock()`. The SDK will not try to use the network, but will pretend to be sending events to Reblaze and receiving acknowledgements from the server. In your test, you can define mock remote configuration and/or mock connection failure (with delay):

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
reblaze.setMockResponse(200, "{'name':'mockConfig', 'interval':30}")
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[reblaze setMockResponse:200 remoteConfig:@"{'name':'mockConfig', 'interval':30}"]
```

{% endtab %}
{% endtabs %}

or

```swift
reblaze.setMockResponse(503, "", 600)
```

Once you enable mocking, you cannot turn it off. Therefore, this feature should never be used in production.

## How to Set up the SDK on Your Platform <a href="#how-to-set-up-the-sdk-on-your-platform" id="how-to-set-up-the-sdk-on-your-platform"></a>

Follow these instructions for your specific platform:

* [Android](/mobile-sdk-v2.2.x/android.md)
* [iOS](/mobile-sdk-v2.2.x/ios.md)
* [Flutter](/mobile-sdk-v2.2.x/flutter.md)
* [React Native](/mobile-sdk-v2.2.x/react-native.md)
