Overview
Kubian Attestation is an advanced security layer designed to verify the integrity of your application and the hardware it is running on. This service exclusively supports Android/mobile devices and VR headsets.
By utilizing the device's hardware Keystore and dynamic validation, it provides a high degree of confidence that the application binary matches your official build and the environment is untampered.
Hardware Pre-Authentication & Anti-Abuse Architecture
To prevent API abuse, botting, and unauthorized emulated requests, Kubian utilizes a strict
pre-authentication layer before any application-level attestation or initialization occurs. This is
handled by a dedicated core library (libKubianHardwareCertification.so).
How Pre-Authentication Works
- Hardware Certificate Generation: Before communicating with any platform endpoints, the device generates a local hardware-backed Elliptic Curve KeyPair (enforcing StrongBox on supported devices).
- One-Time Device Authentication: The raw hardware certificate chain is securely sent to a protected, unexposed Kubian backend endpoint. The server validates the hardware root of trust and issues a short-lived, encrypted ephemeral device certificate.
- Gating All Subsequent Requests: This ephemeral device certificate is required
as a prerequisite. Both the base platform initialization (
libKubianPlatform.so) and the secure attestation pipeline (libKubianSecurePlatform.so) must present this valid device certificate to prove they are operating on authentic hardware before any application-level attestation begins.
This architecture ensures that scripts or customized clients cannot simply spam the attestation APIs; every single session must first mathematically prove its hardware authenticity at the lowest level, effectively eliminating automated API abuse.
The Challenge & Integrity Token Pipeline
Kubian's native attestation employs a two-stage cryptographic exchange pipeline to establish hardware authenticity. Both tokens are short-lived JWTs signed with your project's RSA key (PS256) or HMAC secret (HS512) and carry a 10-minute expiration — they are single-use artifacts designed for immediate exchange, not persistent credentials.
Phase 1 — challenge_token
The client packages its hardware attestation certificate chain alongside device signals (Android ID,
Build Fingerprint) and the ephemeral device certificate obtained during
pre-authentication, and sends them to the Kubian server at
/platform_integrity/get-challenge-token.
On the server, Kubian performs the following immediately:
- Validates the full X.509 certificate chain signature by-link, verifying each intermediate certificate against its issuer.
- Checks the root certificate against trusted Google Root Certificates (GRCs) and known VR hardware certificate keys. Any unknown root is flagged as compromised.
- Extracts and parses the Android Key Attestation ASN.1 extension from the leaf certificate to read hardware-reported fields: security level, verified boot state, bootloader lock status, OS patch level, OS version, package name, and application certificate digest.
- Determines the serial number of the intermediate certificate as the
Device_Certificate_Id(AUD) that the client must return in Phase 2. - Bundles all validated data into a signed JWT — the
challenge_token— which expires in 10 minutes.
challenge_token is not meant to be
stored. It carries the full validated device snapshot and must be exchanged for an
integrity_token immediately. A token that expires before exchange requires the client
to restart the attestation flow from the beginning.
Phase 2 — integrity_token
The client sends the challenge_token alongside the Device_Certificate_Id it
independently extracted from its local hardware certificate to
/platform_integrity/get-integrity-token.
The server then:
- Verifies the
challenge_tokensignature using the project's key — any tampering invalidates it immediately. - Decodes all previously validated device state from the token (application SHA-256 digest, package identifier, device standing, trust level, verified boot data, OS patch level).
- Cross-references the application SHA-256 digest and package identifier against your project's
registered values, producing
RecognizedApplication/NotRecognizedApplicationandRecognizedPackage/NotRecognizedPackageresults. - Repackages everything into the final signed
integrity_tokenJWT, which your backend receives and verifies.
The integrity_token is the fully authenticated JWT payload your client passes to your
own backend for final verification. It inherits the same expiration timestamp as the
challenge_token it was derived from — reinforcing that the entire attestation flow is
designed to complete within a single short-lived session.
challenge_token without the correct matching Device_Certificate_Id will
fail at Phase 2. The client must independently derive this identifier from its own hardware — it
cannot be guessed from the token alone.
Attestation Defenses
Kubian Attestation employs hardware-backed integrity mechanisms utilizing native C++ JNI, Android KeyStore, and secure backend validation. The core defenses include:
- Native JNI Execution: Critical generation and communication workflows are
executed in compiled C++ (
libKubianSecurePlatform.so). This bypasses vulnerable C# or Java execution layers, making memory hooking or analysis significantly harder. - Hardware Cryptographic Binding & Nonce Verification: A server-issued nonce is bound directly into a hardware-backed Elliptic Curve KeyPair generated within the Android KeyStore. This mathematically prevents MITM replays and token harvesting, as the challenge is tied directly to the secure enclave.
- StrongBox Enforcement (Where Available): The native library actively prefers Android StrongBox for cryptographic operations on supported devices (Android 9+). This ensures keys are processed in a physically separated, high-security chip. If unavailable, it enforces the standard TEE (Trusted Execution Environment).
- Deep ASN.1 Certificate Chain Extraction: The native bridge directly extracts the generated x.509 certificate chain from the KeyStore and parses the raw ASN.1 structure of the intermediate hardware certificates to isolate device-specific target AUD identifiers.
- Device Signal Gathering: Securely queries hardware-level identifiers such as
Settings.Secure.ANDROID_IDand the immutableBuild.FINGERPRINTdirectly through native JNI reflection to pair with the cryptographic attestation. - Secure Two-Step Pipeline Validation: The validation happens in a two-stage
network pipeline directly from C++. The initial payload securely requests an intermediary
challenge_token, which is then exchanged alongside the rawDevice_Certificate_Idfor the final authenticatedintegrity_token. - Verified Boot & Bootloader Integrity (Server-Side): The backend asserts
that the hardware
VerifiedBootstatus is officially trusted and the bootloader is properly locked. - Minimum OS Patch Enforcement (Server-Side): The backend strictly rejects devices running heavily outdated or vulnerable Android security patch levels (enforcing a minimum patch level of January 2026).
- Hardware Revocation List (CRL) Validation (Server-Side): The system actively cross-references intermediate device certificates against revocation databases to mass-block compromised device families or bad actors.
Migration to Native Libraries (libKubianPlatform.so & libKubianSecurePlatform.so)
Kubian has moved from a C#-only initializer to compiled native C++ libraries loaded via JNI
(libKubianPlatform.so and libKubianSecurePlatform.so). The thin C# wrapper
classes (via [DllImport]) are all that ever touch managed code. Below is why this
matters and how they work:
What libKubianPlatform.so Does
- Platform Initialization (
KubianPlatform_Init): Accepts the JVM pointer and Android Context from Unity, attaches a native thread to the JVM, queriesSettings.Secure.ANDROID_IDdirectly via JNI reflection, and issues an authenticated GET to the Kubian core endpoint to exchange the device identifier for an OA token and nonce — all without ever touching the C# or Java layer. - Entitlement Check (
KubianPlatform_AppEntitlementCheck): Reads the previously stored OA token and nonce under a mutex, then fires a second authenticated GET to the entitlement endpoint. The entire token lifecycle lives in native memory, never surfacing to the managed heap. - State Accessors: Expose atomic read access to the initialization flag and the cached credential strings. Pointers are returned directly.
What libKubianSecurePlatform.so Does
- Dependency Verification: Dynamically loads
libKubianPlatform.soviadlopento verify that the platform is properly initialized (viaKubianPlatform_IsInitialized) before proceeding. - Hardware Cryptographic Generation: Initializes the Android
KeyStorenatively. It generates an Elliptic Curve (EC) KeyPair directly bound to a hardware attestation challenge (the provided nonce). It strictly enforces StrongBox-backed key generation on supported devices (Android 9+). - ASN.1 Deep Parsing: Extracts the raw DER-encoded X.509 certificate chain from the KeyStore. It manually traverses the ASN.1 structure to extract the Device Certificate ID (AUD) from the intermediate hardware certificate.
- Secure Pipeline Execution: Performs a two-stage POST request directly via
native JNI reflection. It first requests a
challenge_tokenusing the device identifiers (ANDROID_ID and FINGERPRINT), and then requests the finalintegrity_tokensecurely.
Why Native Libraries Instead of a Pure C# Initializer?
- Hardened Against Hooking: A pure C# class in Unity can be read, decompiled, and
patched at runtime with tools like UnityExplorer, dnSpy, or a simple IL2CPP dump. Compiled C++
lives in stripped
.sofiles and requires a debugger attached at the native layer — a significantly higher bar. - Credential Isolation: The OA token, nonce, and attestation payloads never exist
as managed
stringobjects on the garbage-collected heap. They sit in nativestd::stringstorage, out of reach of managed memory scanners. - Direct Android API Access: Hardware key generation, certificate extraction, and
ANDROID_IDquerying are obtained via raw JNI, bypassing any Unity or Mono abstraction that could be shimmed. - Async Without Coroutines: The libraries use
std::threaddetached workers and C-style callbacks. This makes it impossible to pause, cancel, or inspect the flow from Unity's coroutine scheduler.
Developer Responsibilities & Best Practices
To maintain maximum security, developers must not rely solely on a one-time check at startup. It is your responsibility to implement the following practices:
- Secure Nonces: Generate a cryptographically secure, unpredictable nonce on your server. Do not rely on sequential numbers.
- Expiration Tracking: Track the expiration of the nonce on your backend to prevent replay attacks.
- Re-verification: Recheck user attestation during important, high-stakes game actions. This includes leaving/joining rooms, purchasing items, trading, and entering competitive modes.
Backend Verification Update
When calling your backend verification endpoint, the verification process utilizes a direct server-to-server validation method. The authentication is handled by
Kubian which the
developer will only need to verify the nonce they sent.
Headers:
Authorization: OA|{project-app-id}|{project-app-secret}- OAuth style authorization for your project. Do NOT put any app-secrets in the Unity Client. Keep everything in a secure backend server.
The Developer Nonce Approach:
When Kubian successfully processes the payload and verifies the device's hardware, the successful JSON response will contain a
developer-nonce. Your backend must verify that
this returned nonce matches the exact nonce you originally assigned to the client and or
signature checking. If it matches/good signature, the client is verified. If it does
not match/bad signature, reject the client immediately to prevent replay attacks.
Token Verification
Endpoint to verify the validity of an attestation token generated by a device.
Verification API
https://kubian.staticlabs.app/platform_integrity/verify_integrity_token
Required Headers
| Header | Description | Example |
|---|---|---|
Authorization |
OAuth style authorization for your project combining the prefix OA, your App Id, and your App Secret separated by a pipe character. | OA|your-app-id|your-app-secret |
JSON Body
| JSON | Description | Example |
|---|---|---|
integrity_token |
Attestation Token passed from the client to your secure developer backend server, that will be sent to kubian verification servers. To verify the application authenticity & device authenticity. | {"integrity_token": "example-token-jwt"} |
Possible Responses
| Scenario | HTTP Status | Response Body |
|---|---|---|
| Success (Device Trusted) | 200 OK | {"success": true, "status": "DEVICE_PASS", "developer-nonce": "Your-Secure-Server-Nonce", "unique_id": "device-unique-id"}
|
| Missing/Invalid Auth | 400 Bad Request | {"success": false, "status": "BAD_REQUEST", "message": "Invalid request. Missing 'Authorization' header."}
|
| Application not found. App secret or App ID may be incorrect | 404 Not Found | {"success": false, "status": "UNKNOWN_PROJECT", "message": "This application does not exist. Please retry with a different application ID."}
|
| App Mismatch / Spoof | 401 Unauthorized | {"success": false, "status": "APPLICATION_SHA256_NOT_RECOGNIZED", "unique_id": "device-unique-id"}
|
| App Package Identifier Mismatch | 401 Unauthorized | {"success": false, "status": "APPLICATION_PACKAGE_NOT_RECOGNIZED", "unique_id": "device-unique-id"}
|
| Device Compromised (e.g. Tampered/Rooted) | 401 Unauthorized | {"success": false, "status": "GENERAL_INTEGRITY_FLAW", "unique_id": "device-unique-id"}
|
| Device Hardware Batch Revoked (X.509 Certificate List Ban) | 403 Forbidden | {"success": false, "status": "DEVICE_INTERMEDIATE_HARDWARE_CERTIFICATE_REVOKED", "unique_id": "device-unique-id"}
|
| Device Banned | 403 Forbidden | {"success": false, "status": "DEVICE_BANNED", "unique_id": "device-unique-id"}
|
| Device Integrity Compromised (e.g. Rooted, Hooked) | 403 Forbidden | {"success": false, "status": "DEVICE_INTEGRITY_COMPROMISED", "unique_id": "device-unique-id"}
|
| Device OS Outdated | 403 Forbidden | {"success": false, "status": "DEVICE_OS_OUTDATED", "unique_id": "device-unique-id"}
|
| Device Boot loader Integrity Failed | 400 Bad Request | {"success": false, "status": "DEVICE_BOOT_LOADER_INTEGRITY_FAILED", "unique_id": "device-unique-id"}
|
| Device Boot Integrity Failed | 401 Unauthorized | {"success": false, "status": "DEVICE_BOOT_INTEGRITY_FAILED", "unique_id": "device-unique-id"}
|
| Device Integrity Standard Unmet | 401 Unauthorized | {"success": false, "status": "DEVICE_INTEGRITY_STANDARD_UNMET", "unique_id": "device-unique-id"}
|
| Intermediate Hardware Certificate Missing | 400 Bad Request | {"success": false, "status": "DEVICE_INTERMEDIATE_HARDWARE_CERTIFICATE_MISSING"}
|
| Intermediate Hardware Certificate Invalid | 400 Bad Request | {"success": false, "status": "DEVICE_INTERMEDIATE_HARDWARE_CERTIFICATE_INVALID"}
|
| Project Suspended | 403 Forbidden | {"success": false, "status": "UNKNOWN_PROJECT", "message": "Project has been suspended by administrator."}
|
| Project Payment Past Due | 402 Payment Required | {"success": false, "status": "REQUEST_UNSATISFIED", "message": "Project payment is past due..."}
|
| Token Expired | 401 Unauthorized | {"success": false, "status": "INTEGRITY_TOKEN_EXPIRED"} |
| Token Signature Invalid | 401 Unauthorized | {"success": false, "status": "INTEGRITY_TOKEN_INVALID"} |
| Token Missing Segments | 400 Bad Request | {"success": false, "status": "INTEGRITY_TOKEN_MISSING_SEGMENTS"} |
| Application Information Missing | 400 Bad Request | {"success": false, "status": "FAILURE_ERROR: DEVICE DID NOT PROVIDE APPLICATION INFORMATION"}
|
Hardware Revoked List
Revocation List URL
https://kubian.staticlabs.app/platform_integrity/hardware-intermediate/revoked
Endpoint to retrieve a detailed list of all bad actors, flagged hardware, and permanently suspended (blacklisted) devices.
Method: GET
Example Response
{
"entries": {
"a1b2c3d4e5f6g7h8i9j0": {
"status": "REVOKED",
"reason": "KEY_COMPROMISE"
}
}
}
Core Initialization & Entitlement
Before any hardware attestation checks can be requested via the Kubian network, the underlying native
components must be properly injected into the Java Virtual Machine (JVM) and bound to your game's
current AndroidJavaObject activity. This bootstrap phase is known as Core
Initialization.
Once initialized, the platform must execute an App Entitlement Check. This procedure confirms that the device has properly registered with Kubian servers and that your developer account is in good standing. It is not a substitute for hardware attestation — it is a prerequisite that ensures the native layer is correctly initialized and reachable before the attestation pipeline begins.
KubianSecurePlatform.Attestation.GetIntegrityToken.
What Core Initialization Does (/user/client_information/core)
When KubianPlatform.Core.Initialize is called, libKubianPlatform.so issues
a GET request to the /user/client_information/core endpoint with your
app_id and the device's android_id. The server validates that your
app_id corresponds to a registered project, then looks up or creates a session entry
for this device. On success, it returns an OA token and a nonce —
both stored exclusively in native memory within libKubianPlatform.so, never surfacing
to the managed C# heap. This token pair is the credential the entitlement check will later validate.
- Validates the
app_idagainst registered projects. - Retrieves or creates a device-bound OA token and nonce for the given Android ID.
- Returns credentials only if the project exists and is reachable — any failure here means the platform is not safe to proceed with.
What App Entitlement Does (/user/app_entitlement_check/android)
Following a successful initialization, KubianPlatform.Core.AppEntitlement reads the
stored OA token and nonce from native memory and issues a GET request to the
/user/app_entitlement_check/android endpoint. The server cross-references the token and
nonce against the stored device entry for your project. If the token is valid and the nonce matches
the issued credential, the server confirms entitlement. If the project has no known users, the token
is invalid, or the nonce does not match, the check fails.
- Validates that the OA token and nonce issued during Core Initialization are still active and correctly paired.
- Confirms that the calling application belongs to a project with known registered devices.
- Does not check hardware integrity, application signature, or OS state — that is the job of the attestation pipeline.
The Initialization Sequence
The KubianPlatform.Core.Initialize method acts as the entry point for the Kubian engine.
What happens under the hood?
- The C# wrapper accesses
com.unity3d.player.UnityPlayerto obtain the active JVM pointer. - The native
libKubianPlatform.solibrary is invoked via JNI (Java Native Interface). - Global references to your Unity Android Context are created to allow asynchronous background execution without blocking the main game thread.
- Kubian sets up memory constraints and hooks required for environment telemetry.
error string. If
initialization fails, you must not proceed with entitlement or attestation, as the underlying native
structures will result in an immediate application crash (SIGSEGV).
App Entitlement
Following a successful initialization, the application must immediately call
KubianPlatform.Core.AppEntitlement.
Mechanism of Action
- The API sends an encrypted payload containing the device's basic telemetry and the provided
AppIdto the Kubian backend. - The backend verifies the active subscription status for the application.
- If the project is suspended, unpaid, or the request originates from an unregistered package name, the backend actively rejects the connection.
Implementation Example
The following example demonstrates a robust, production-ready implementation of the Core
Initialization and App Entitlement sequence. You must provide a valid AppId registered
in your Kubian developer dashboard.
using Kubian.Platform;
using UnityEngine;
public class KubianBootstrapper : MonoBehaviour
{
private const string AppId = "YOUR_KUBIAN_APP_ID";
void Start()
{
InitializeCore();
}
private void InitializeCore()
{
Debug.Log("[Kubian] Initializing Core Platform...");
KubianPlatform.Core.Initialize(AppId, (initError) =>
{
if (!string.IsNullOrEmpty(initError))
{
// FATAL: The platform could not bind to the JVM or invalid AppId
Debug.LogError("[Kubian] Core Initialization Failed: " + initError);
HandleFailure("Failed to initialize security engine.");
return;
}
Debug.Log("[Kubian] Core Initialized. Requesting App Entitlement...");
KubianPlatform.Core.AppEntitlement(AppId, (entitlementResult, entitlementError) =>
{
if (!string.IsNullOrEmpty(entitlementError))
{
// FATAL: App is not entitled, subscription expired, or network failure
Debug.LogError("[Kubian] Entitlement Check Failed: " + entitlementError);
HandleFailure("Application entitlement could not be verified.");
return;
}
Debug.Log("[Kubian] Entitlement Verified. Ready for Attestation.");
// At this point, the platform is ready. You can now fetch the challenge
// nonce from your server and invoke GetIntegrityToken().
ProceedToAttestation();
});
});
}
private void HandleFailure(string reason)
{
// Implement logic to gracefully kick the player back to the main menu
// or prevent them from entering multiplayer matches.
}
private void ProceedToAttestation()
{
// Proceed to generate challenge_nonce and call KubianSecurePlatform.Attestation.GetIntegrityToken
}
}
Integration Example
The Kubian platform handles the heavy lifting for you through the native
libKubianPlatform.so library. The thin C# wrapper class KubianPlatform is
all your game code ever needs to touch. Below is the complete attestation flow following a
successful Core Initialization and App Entitlement.
Attestation Request Example
using Kubian.Platform.Security;
using System.Security.Cryptography;
// The "challenge_nonce" parameter must be a non-wrapping Base64URL-encoded
// string, formed from a random byte array by the application server.
string GetChallengeNonceFromAppServer()
{
byte[] randomBytes = new byte[16];
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(randomBytes);
}
// Convert to Base64 string
string base64Nonce = Convert.ToBase64String(randomBytes);
// Replace standard Base64 characters to make it URL safe
string challenge_nonce = base64Nonce.Replace('+', '-').Replace('/', '_');
// The length of the challenge_nonce must range from 22 to 172 characters.
return challenge_nonce;
}
void SampleCode()
{
string challenge_nonce = GetChallengeNonceFromAppServer();
Debug.Log("Calling the Attestation API");
KubianSecurePlatform.Attestation.GetIntegrityToken(AppId, challenge_nonce, "").OnComplete((token, error) => {
if (!string.IsNullOrEmpty(token))
{
StartCoroutine(SubmitToBackend(token));
}
else
{
if (AuthenticationStatus != null) AuthenticationStatus.text = error;
isAuthenticating = false;
}
});
}
Understanding the Verification Response
Once your backend successfully verifies the integrity_token via the Kubian API, the server will issue a JSON payload. Below is an example of what a successful response looks like:
{
"success": true,
"status": "DEVICE_PASS",
"developer-nonce": "Your-Secure-Server-Nonce",
"unique_id": "device-unique-id"
}
Note: Your backend's primary duty upon receiving this success message is to extract
developer-nonce and assert that it precisely matches the nonce you generated for the
user's session. The honeypot and debug fields are embedded traps for malicious actors attempting to
reverse engineer responses; do not build logic around them.
Attestation Outcomes & Status Definitions
The device state is determined through a combination of keystore features and environment checks. These evaluations happen internally on the Kubian servers, leading to either a success response or an error code depending on the device's integrity.
1. Security Level
Device Status is verified in our secure backend servers verifying the client's AB (Attestation-Bytes) from the hardware. Verifying against Google Root Certificates (GRCs) with overall low false positives in testing. If this is not in a trusted category it is an extremely high chance that the client is using a spoofed Hardware Root Certificate.
| Status | Description |
|---|---|
| Advanced | Backed by Android StrongBox. The key is isolated in a separate, highly secure hardware chip. |
| Basic | Backed by a Trusted Execution Environment (TEE). Secure, but utilizing the main processor's secure enclave. |
| NotTrusted | Unable to determine or was generated from Software-Level. A common sign of the device / application being compromised. |
2. Device Standing
General state of the operating environment. A safe device returns Normal internally. Anything else results in an Unauthorized or Forbidden response.
| Standing | Signals Triggered |
|---|---|
| Normal | No common threats found. |
| Rooted | Indicates Superuser binaries (su) or test-keys were found. |
| Debugger | A live debugger is currently attached to the application process. |
| Emulator | The environment matches known emulators or SDK images. |
| Hooked | Tamper frameworks (e.g., Frida, Xposed, Magisk, Zygisk) were detected injecting into memory. |
| Compromised | The device is likely compromised. Happens due to the device being used by an emulator, spoofed root certificate keys, or an unknown device. |
3. Verified Boot
Reflects the integrity of the operating system booting process.
| Status | Description |
|---|---|
| Trusted | The OS is official with no immediate threats reported by the Hardware. |
| Unofficial | The OS has been replaced and is most likely compromised. |
| NotTrusted | The OS has been modified and re-signed by an unknown publisher. |
| Compromised | The OS has been compromised and all security has been stripped away. |
| Unknown | Kubian was unable to determine if the OS was legitimate or not. |
Our Research & Resources
Kubian aims to improve the fields of Game Security and Cybersecurity by maintaining a balance between our research and security. While we do not disclose sensitive implementation details that may weaken our systems, we provide insights and resources to support research, understanding, and responsible development.
Resources Used for Device-Level Security (Secure Backend Server)
The following resources and methodologies contribute to Kubian's layered device integrity validation system.
| Name | Description |
|---|---|
| GRCs (Google Root Certificates) | Hardware-backed public attestation certificates used to verify device authenticity. Resource: https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate |
| VR Hardware Certificate Keys | Kubian collects and validates hardware root certificates from VR devices when necessary to improve compatibility and reduce false positives. |
| ARC Database | A curated dataset of trusted hardware attestation root certificates used to validate hardware authenticity and detect untrusted keys. |
| ASN.1 Analysis | Kubian processes and decodes ASN.1 attestation payloads to extract verified hardware-backed information. |
| Device Risk Signals | Derived from a combination of internal analysis and platform-level integrity mechanisms, intended to assist in making security decisions. |
| DHSAR | Deep Hardware Security Analysis Reporting focuses on evaluating overall device integrity rather than only application integrity. |
| DHASR | Deep Hardware Application Security Reporting extends hardware validation to application integrity by verifying hardware-reported keystore signatures against developer-provided application data. |
Developer Best Practices
- Do Not Block Main Thread: The native callbacks are inherently asynchronous. Do not
use
Thread.Sleepor blockingwhileloops waiting for the callbacks to resolve. - Retry Logic: If the App Entitlement check fails due to a network timeout, implement a backoff-retry mechanism before fully disconnecting the user.
- Obfuscation: Ensure your Unity assemblies (especially the ones handling the success callbacks) are run through an obfuscator (e.g., IL2CPP + string encryption) to prevent trivial bypassing of the entitlement flow.