Skip to Content
SDK IntegrationKotlin (Android & JVM)

Android / Kotlin SDK

Integrate TrustPin into your Android or JVM application for native certificate pinning.

Current version: cloud.trustpin:kotlin-sdk 5.0.0

Platform Requirements

PlatformMinimum Version
AndroidAPI 25+ (full feature support)
JVMJava 11+

Kotlin Version: 2.3.0+

Note: The Maven Central artifact is an Android AAR. For server-side JVM, desktop, or Compose Multiplatform targets, request access to the hardened JVM JAR via support@trustpin.cloud.


Installation

Gradle (Kotlin DSL)

Add TrustPin to your build.gradle.kts:

dependencies { implementation("cloud.trustpin:kotlin-sdk:5.0.0") }

Gradle (Groovy)

Add to your build.gradle:

dependencies { implementation 'cloud.trustpin:kotlin-sdk:5.0.0' }

Maven

Add to your pom.xml:

<dependency> <groupId>cloud.trustpin</groupId> <artifactId>kotlin-sdk</artifactId> <version>5.0.0</version> </dependency>

Quick Start

1. Get Your Credentials

Sign in to the TrustPin Dashboard  and retrieve:

  • Organization ID
  • Project ID
  • Public Key (Base64-encoded)

2. Initialize TrustPin

Ship a trustpin.json asset in your app and load it with TrustPinConfiguration.fromAssets(context). Credentials stay out of source.

Place trustpin.json at app/src/main/assets/trustpin.json:

{ "organization_id": "your-org-id", "project_id": "your-project-id", "public_key": "your-base64-public-key", "mode": "strict" }

Build-variant overrides follow standard Android source-set merging — drop a different file under src/debug/assets/trustpin.json or src/staging/assets/trustpin.json to use per-flavor credentials.

KeyTypeRequiredNotes
organization_idStringYesNon-empty
project_idStringYesNon-empty
public_keyStringYesBase64-encoded ECDSA P-256 public key
modeStringNo"strict" (default) or "permissive"
configuration_urlStringNoMust be HTTPS. Overrides the default CDN endpoint

Then load it during Application.onCreate():

import android.app.Application import cloud.trustpin.kotlin.sdk.TrustPin import cloud.trustpin.kotlin.sdk.TrustPinConfiguration import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class MyApplication : Application() { override fun onCreate() { super.onCreate() CoroutineScope(Dispatchers.IO).launch { try { val config = TrustPinConfiguration.fromAssets(this@MyApplication) TrustPin.setup(config) TrustPin.requirePinned() println("TrustPin initialized") } catch (e: Exception) { println("TrustPin setup failed: ${e.message}") } } } }

TrustPin.requirePinned() is a belt-and-suspenders gate — call it once after setup, immediately before constructing any HTTP client that depends on pinning, to fail loudly if the configuration didn’t load.

Don’t forget to register your Application class in AndroidManifest.xml:

<application android:name=".MyApplication" ...> </application>

3. Add Network Permission

Ensure your AndroidManifest.xml includes:

<uses-permission android:name="android.permission.INTERNET" />

Integration Approaches

ApproachBest ForSetup Complexity
OkHttp Integration (Recommended)Most Android apps🟢 Low
Retrofit IntegrationREST API clients (uses OkHttp under the hood)🟢 Low
Ktor Client IntegrationKtor-based apps and KMP shared modules🟡 Medium
Manual VerificationCustom transports, non-OkHttp stacks🟠 High

TrustPinSSLSocketFactory.create() returns an SSL socket factory wired to your TrustPin configuration. Pass it — along with its trust manager — to OkHttpClient.Builder:

import cloud.trustpin.kotlin.sdk.ssl.TrustPinSSLSocketFactory import okhttp3.OkHttpClient import java.util.concurrent.TimeUnit val sslSocketFactory = TrustPinSSLSocketFactory.create() val httpClient = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .sslSocketFactory(sslSocketFactory, sslSocketFactory.trustManager()) .build()

Retrofit Integration

Retrofit uses OkHttp under the hood — share the same TrustPin-backed client:

class ApiClient { private val okHttpClient by lazy { val sslSocketFactory = TrustPinSSLSocketFactory.create() OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .sslSocketFactory(sslSocketFactory, sslSocketFactory.trustManager()) .build() } private val retrofit by lazy { Retrofit.Builder() .baseUrl("https://api.example.com/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() } }

Ktor Client Integration

Plug TrustPin into Ktor’s OkHttp engine:

import io.ktor.client.* import io.ktor.client.engine.okhttp.* import okhttp3.OkHttpClient private val httpClient by lazy { val sslSocketFactory = TrustPinSSLSocketFactory.create() HttpClient(OkHttp) { engine { preconfigured = OkHttpClient.Builder() .sslSocketFactory(sslSocketFactory, sslSocketFactory.trustManager()) .build() } } }

Manual Verification

For custom transports, validate a domain/certificate pair directly with the suspending API:

import java.security.cert.X509Certificate val certificate: X509Certificate = /* ... */ TrustPin.verify("api.example.com", certificate)

Named Instances (Multi-Tenant)

The SDK supports independent named instances via TrustPin.instance(id) for apps that talk to multiple TrustPin projects (for example, separate consumer and admin backends). Because the bundled-asset path loads a single trustpin.json per build, multi-tenant setups currently require the programmatic configuration API — see the upstream Kotlin SDK docs  for usage.


Logging

Set the desired verbosity before calling setup() to capture initialization logs:

import cloud.trustpin.kotlin.sdk.TrustPinLogLevel TrustPin.setLogLevel(TrustPinLogLevel.INFO)

Available levels: NONE, ERROR, INFO, DEBUG.


Error Handling

TrustPinError is a sealed class with the following variants:

VariantMeaning
DomainNotRegisteredStrict mode and the host isn’t in the configuration
PinsMismatchServer certificate doesn’t match any active pin
AllPinsExpiredConfiguration is stale — rotate pins in the dashboard
InvalidServerCertServer returned an unparseable certificate
InvalidProjectConfigBad credentials or invalid configuration
ErrorFetchingPinningInfoNetwork failure while loading the configuration
ConfigurationValidationFailedJWS signature didn’t verify against the project’s public key
NotInitializedAn API was called before setup() completed successfully
UnsupportedDeviceThe runtime environment doesn’t support the required security primitives
try { TrustPin.setup(config) } catch (e: TrustPinError.InvalidProjectConfig) { // Bad credentials } catch (e: TrustPinError.ErrorFetchingPinningInfo) { // Network failure during setup } catch (e: TrustPinError.NotInitialized) { // setup() wasn't called, or it failed silently — guard with requirePinned() } catch (e: TrustPinError) { // Any other TrustPin failure (UnsupportedDevice, etc.) }

Best Practices

Setup & Initialization

  1. Initialize in Application.onCreate() for app-wide coverage.
  2. Use a coroutine scope for async setup — the 5.0 API is suspend-only.
  3. Call TrustPin.requirePinned() after setup(), before constructing any HTTP client that depends on pinning.
  4. Set the log level before setup() to capture initialization output.
  5. Handle setup errors gracefully — don’t block app launch.

Security

  1. Use TrustPinMode.STRICT in production.
  2. Prefer SPKI pinning; rotate pins in the dashboard before they expire.
  3. Monitor pin validation failures.
  4. Keep credentials outside source control — prefer TrustPinConfiguration.fromAssets(context) with per-flavor trustpin.json files, or fetch them at runtime and use withAndroidStorage(context).
  5. Use HTTPS for all pinned domains.

Performance

  1. Configuration is cached for 10 minutes with a stale-while-revalidate fallback.
  2. Reuse OkHttpClient instances rather than creating one per request.
  3. Use minimal log levels in production.

Complete Documentation

For the full API reference, ProGuard/R8 rules, and additional integration patterns, visit:

TrustPin Kotlin API Reference 


Resources