Skip to Content
SDK IntegrationKotlin (Android & JVM)

Android SDK

Integrate TrustPin into your Android application for comprehensive certificate pinning security.

Platform Requirements

PlatformMinimum VersionFeatures
AndroidAPI 21 (Android 5.0 Lollipop)OkHttp interceptor, TrustManager, SSL Socket Factory
JVMJava 11+SSL Socket Factory, Manual verification

Kotlin Version: 1.9.0+

Note: While the SDK supports Android API 21+, we recommend API 23+ (Android 6.0 Marshmallow) for improved security features and TLS 1.2 support by default.


Installation

Gradle (Kotlin DSL)

Add TrustPin to your build.gradle.kts:

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

Gradle (Groovy)

Add to your build.gradle:

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

Maven

Add to your pom.xml:

<dependency> <groupId>cloud.trustpin</groupId> <artifactId>kotlin-sdk</artifactId> <version>2.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

Add this to your Application class:

import cloud.trustpin.kotlin.sdk.TrustPin import cloud.trustpin.kotlin.sdk.TrustPinMode import android.app.Application import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.launch class MyApplication : Application() { override fun onCreate() { super.onCreate() lifecycleScope.launch { try { TrustPin.setup( organizationId = "your-org-id", projectId = "your-project-id", publicKey = "your-base64-public-key", mode = TrustPinMode.STRICT ) println("TrustPin initialized") } catch (e: Exception) { println("TrustPin setup failed: ${e.message}") } } } }

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 with OkHttp

The easiest way to integrate TrustPin with OkHttp:

import cloud.trustpin.kotlin.okhttp.TrustPinOkHttpInterceptor import okhttp3.OkHttpClient val client = OkHttpClient.Builder() .addInterceptor(TrustPinOkHttpInterceptor()) .build() // Use with Retrofit val retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .build()

SSL Socket Factory

For direct OkHttp configuration:

import cloud.trustpin.kotlin.okhttp.TrustPinSSLSocketFactory import okhttp3.OkHttpClient val client = OkHttpClient.Builder() .sslSocketFactory( TrustPinSSLSocketFactory(), TrustPinX509TrustManager() ) .build()

Integration with HttpsURLConnection

Global Configuration

Set TrustPin globally for all HttpsURLConnection requests:

import cloud.trustpin.kotlin.okhttp.TrustPinSSLSocketFactory import javax.net.ssl.HttpsURLConnection // Apply globally HttpsURLConnection.setDefaultSSLSocketFactory(TrustPinSSLSocketFactory()) // Now all HttpsURLConnection requests use certificate pinning val connection = URL("https://api.example.com/data") .openConnection() as HttpsURLConnection

Per-Connection Configuration

Apply to specific connections:

import cloud.trustpin.kotlin.okhttp.TrustPinSSLSocketFactory val connection = URL("https://api.example.com/data") .openConnection() as HttpsURLConnection connection.sslSocketFactory = TrustPinSSLSocketFactory()

Manual Certificate Verification

Verify certificates programmatically:

import cloud.trustpin.kotlin.sdk.TrustPin import cloud.trustpin.kotlin.sdk.TrustPinError try { TrustPin.verify( domain = "api.example.com", certificate = pemCertificateString ) println("Certificate is valid and pinned") } catch (error: TrustPinError.PinsMismatch) { println("Certificate doesn't match configured pins") } catch (error: TrustPinError.DomainNotRegistered) { println("Domain not configured for pinning") } catch (error: TrustPinError.AllPinsExpired) { println("All pins have expired for this domain") } catch (error: TrustPinError) { println("Verification error: ${error.message}") }

Configuration

Pinning Modes

Strict Mode

Rejects connections to unregistered domains:

TrustPin.setup( organizationId = "your-org-id", projectId = "your-project-id", publicKey = "your-base64-public-key", mode = TrustPinMode.STRICT // Recommended for production )

Permissive Mode

Allows unregistered domains to bypass pinning:

TrustPin.setup( organizationId = "your-org-id", projectId = "your-project-id", publicKey = "your-base64-public-key", mode = TrustPinMode.PERMISSIVE // For development/testing )

Logging

Configure logging levels:

import cloud.trustpin.kotlin.sdk.TrustPinLogLevel // Set log level (default: NONE) TrustPin.setLogLevel(TrustPinLogLevel.DEBUG) // Available levels: // TrustPinLogLevel.NONE - No logging (production) // TrustPinLogLevel.ERROR - Errors only // TrustPinLogLevel.INFO - Errors + informational messages // TrustPinLogLevel.DEBUG - All messages (development)

Error Handling

TrustPin provides comprehensive error types:

import cloud.trustpin.kotlin.sdk.TrustPinError try { TrustPin.verify(domain, certificate) } catch (error: TrustPinError) { when (error) { is TrustPinError.InvalidProjectConfig -> { // Setup or configuration issues println("Invalid configuration") } is TrustPinError.PinsMismatch -> { // Certificate doesn't match pins - SECURITY CRITICAL println("Certificate mismatch - possible MITM attack") } is TrustPinError.DomainNotRegistered -> { // Domain not configured (strict mode only) println("Domain not registered") } is TrustPinError.AllPinsExpired -> { // All pins expired for domain println("Pins expired") } is TrustPinError.InvalidServerCert -> { // Invalid certificate format println("Invalid certificate") } is TrustPinError.ErrorFetchingPinningInfo -> { // Network error fetching configuration println("Network error") } is TrustPinError.ConfigurationValidationFailed -> { // Signature validation failed println("Signature validation failed") } } }

Best Practices

Setup & Initialization

  1. Initialize in Application.onCreate() for app-wide coverage
  2. Use coroutine scope for async setup
  3. Handle setup errors gracefully - don’t block app launch
  4. Set log level before setup for complete logging

Security

  1. Use TrustPinMode.STRICT in production
  2. Monitor pin validation failures
  3. Rotate pins before expiration
  4. Keep credentials secure (use BuildConfig or environment variables)
  5. Use HTTPS for all pinned domains

Performance

  1. Configuration caching is automatic (10-minute TTL)
  2. Reuse OkHttpClient instances
  3. Use TrustPinLogLevel.NONE or ERROR in production
  4. Initialize early in app lifecycle

Development Workflow

  1. Start with TrustPinMode.PERMISSIVE during development
  2. Test all endpoints with pinning enabled
  3. Validate configurations in staging
  4. Switch to TrustPinMode.STRICT for production releases
  5. Use TrustPinLogLevel.DEBUG for troubleshooting

Complete Example

Application Setup

import android.app.Application import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.lifecycleScope import cloud.trustpin.kotlin.sdk.TrustPin import cloud.trustpin.kotlin.sdk.TrustPinMode import cloud.trustpin.kotlin.sdk.TrustPinLogLevel import kotlinx.coroutines.launch class MyApplication : Application() { override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycleScope.launch { // Set log level first TrustPin.setLogLevel( if (BuildConfig.DEBUG) TrustPinLogLevel.DEBUG else TrustPinLogLevel.ERROR ) // Initialize TrustPin try { TrustPin.setup( organizationId = BuildConfig.TRUSTPIN_ORG_ID, projectId = BuildConfig.TRUSTPIN_PROJECT_ID, publicKey = BuildConfig.TRUSTPIN_PUBLIC_KEY, mode = if (BuildConfig.DEBUG) { TrustPinMode.PERMISSIVE } else { TrustPinMode.STRICT } ) } catch (e: Exception) { // Handle gracefully android.util.Log.e("TrustPin", "Setup failed", e) } } } }

Network Client with Retrofit

import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import cloud.trustpin.kotlin.okhttp.TrustPinOkHttpInterceptor object NetworkClient { private val okHttpClient = OkHttpClient.Builder() .addInterceptor(TrustPinOkHttpInterceptor()) .build() val retrofit: Retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() } // Usage interface ApiService { @GET("data") suspend fun getData(): Response<Data> } val apiService = NetworkClient.retrofit.create(ApiService::class.java)

Troubleshooting

Setup Fails with InvalidProjectConfig

  • Verify credentials in TrustPin Dashboard 
  • Check for whitespace or special characters
  • Ensure public key is properly base64-encoded
  • Confirm Application class is registered in manifest

Certificate Verification Fails

  • Confirm domain is registered in dashboard
  • Verify certificate format (must be PEM-encoded)
  • Check pin expiration dates
  • Test with TrustPinMode.PERMISSIVE first

Network Requests Fail

  • Ensure INTERNET permission in manifest
  • Verify TrustPin is initialized before network requests
  • Check for ProGuard/R8 obfuscation issues
  • Enable debug logging to see detailed errors

OkHttp Integration Issues

  • Ensure interceptor is added before other interceptors
  • Verify OkHttp version compatibility (3.x or 4.x)
  • Check that TrustPin setup completed successfully
  • Test with a simple request first

ProGuard/R8 Configuration

If using code obfuscation, add these rules to proguard-rules.pro:

# TrustPin SDK -keep class cloud.trustpin.** { *; } -keepclassmembers class cloud.trustpin.** { *; } # OkHttp (if not already included) -dontwarn okhttp3.** -keep class okhttp3.** { *; }

API Reference

Core Classes

  • TrustPin - Main SDK interface for setup and verification
  • TrustPinMode - Pinning modes (STRICT, PERMISSIVE)
  • TrustPinOkHttpInterceptor - OkHttp interceptor
  • TrustPinSSLSocketFactory - SSL Socket Factory
  • TrustPinError - Error types
  • TrustPinLogLevel - Logging configuration

Key Methods

// Setup suspend fun setup( organizationId: String, projectId: String, publicKey: String, mode: TrustPinMode = TrustPinMode.STRICT ) // Manual verification suspend fun verify(domain: String, certificate: String) // Logging fun setLogLevel(level: TrustPinLogLevel)

Production Deployment

Production Configuration

1. Set Production Mode

import cloud.trustpin.kotlin.sdk.TrustPin import cloud.trustpin.kotlin.sdk.TrustPinMode import cloud.trustpin.kotlin.sdk.TrustPinLogLevel class MyApplication : Application() { override fun onCreate() { super.onCreate() lifecycleScope.launch { // Production configuration TrustPin.setLogLevel(TrustPinLogLevel.ERROR) TrustPin.setup( organizationId = BuildConfig.TRUSTPIN_ORG_ID, projectId = BuildConfig.TRUSTPIN_PROJECT_ID, publicKey = BuildConfig.TRUSTPIN_PUBLIC_KEY, mode = TrustPinMode.STRICT // Always strict in production ) } } }

2. Build Configuration

Add credentials to build.gradle.kts:

android { defaultConfig { // ... buildConfigField("String", "TRUSTPIN_ORG_ID", "\"${System.getenv("TRUSTPIN_ORG_ID")}\"") buildConfigField("String", "TRUSTPIN_PROJECT_ID", "\"${System.getenv("TRUSTPIN_PROJECT_ID")}\"") buildConfigField("String", "TRUSTPIN_PUBLIC_KEY", "\"${System.getenv("TRUSTPIN_PUBLIC_KEY")}\"") } buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } }

3. ProGuard/R8 Rules

Add to proguard-rules.pro:

# TrustPin SDK -keep class cloud.trustpin.** { *; } -keepclassmembers class cloud.trustpin.** { *; } # Prevent stripping of TrustPin error types -keep class cloud.trustpin.kotlin.sdk.TrustPinError { *; } -keep class cloud.trustpin.kotlin.sdk.TrustPinError$* { *; }

4. Google Play Submission

Before publishing to Google Play:

  • Test on multiple devices and Android versions
  • Verify ProGuard/R8 doesn’t break TrustPin
  • Test with internal testing track first
  • Update Data Safety section in Play Console
  • Include attribution in app description

AndroidManifest.xml

Ensure internet permission is declared:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".MyApplication" ...> </application> </manifest>

Resources