trustpin_sdk 4.3.0
trustpin_sdk: ^4.3.0 copied to clipboard
A Flutter plugin for TrustPin SSL certificate pinning SDK that provides enhanced security for network connections by validating SSL certificates against configured pins.
TrustPin SDK for Flutter #
A comprehensive Flutter plugin for TrustPin SSL certificate pinning that provides robust security against man-in-the-middle (MITM) attacks by validating server certificates against pre-configured public key pins.
Get started at TrustPin.cloud | Manage your certificates in the Cloud Console
Table of Contents #
- Features
- Installation
- Platform Setup
- Quick Start
- Advanced Usage
- API Reference
- Error Handling
- Example App
Features #
- SSL Certificate Pinning: Advanced certificate validation using SHA-256/SHA-512 public key pins
- Signed Configuration: Cryptographically signed pinning configurations
- Cross-platform Support: Native implementations for iOS (Swift), Android (Kotlin), and macOS (Swift)
- Flexible Pinning Modes: Support for strict (production) and permissive (development) validation modes
- Certificate Fetching: Built-in
fetchCertificatefor OS-level TLS validation and leaf certificate extraction - HTTP Client Integration: Built-in interceptors for Dio and the http package
- Multiple Instances: Use
TrustPin.sharedfor single-project apps, orTrustPin.instance('id')for libraries and multi-tenant setups - Comprehensive Error Handling: Detailed error types with programmatic checking capabilities
- Configurable Logging: Multiple log levels for debugging, monitoring, and production use
- Thread Safety: Built with Flutter's async/await pattern and native concurrency models
Installation #
Add TrustPin SDK to your pubspec.yaml:
dependencies:
trustpin_sdk: ^4.3.0
Then install the package:
flutter pub get
Platform Setup #
iOS Requirements #
- Minimum iOS Version: 13.0+
- Xcode: 16.3+
- Swift: 6.1+
- Native Dependencies: TrustPinKit 4.3.1 (automatically configured via Swift Package Manager or CocoaPods)
macOS Requirements #
- Minimum macOS Version: 13.0+
- Xcode: 16.3+
- Swift: 6.1+
- Native Dependencies: TrustPinKit 4.3.1 (automatically configured via Swift Package Manager or CocoaPods)
Set
MACOSX_DEPLOYMENT_TARGET = 13.0(or higher) in your Xcode project's build settings. Flutter uses this value to align the generated Swift Package Manager wrapper with TrustPin's minimum platform.
For sandboxed macOS apps, add the network client entitlement:
<!-- In DebugProfile.entitlements and Release.entitlements -->
<key>com.apple.security.network.client</key>
<true/>
Android Requirements #
- Minimum SDK: API 25 (Android 7.1)+
- Compile SDK: API 36
- Kotlin: 2.3.0+
- Native Dependencies: TrustPin Kotlin SDK 4.3.2 (automatically configured via Gradle)
The Flutter plugin declares
minSdk = 25because the underlying TrustPin Kotlin SDK 4.3.2 requires it. Apps consuming the plugin must therefore declareminSdk >= 25in theirandroid/app/build.gradle.
Network Permissions #
The SDK requires network access to fetch pinning configurations from https://cdn.trustpin.cloud.
Android
The plugin automatically includes the required network permission in its AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
iOS / macOS
Network access is enabled by default. No additional configuration required.
Quick Start #
1. Get Your Credentials #
Sign up at TrustPin Cloud Console and create a project to get your:
- Organization ID
- Project ID
- Public Key (Base64-encoded)
2. Initialize the SDK #
import 'package:trustpin_sdk/trustpin_sdk.dart';
Future<void> initializeTrustPin() async {
// Optional: enable debug logging during development
await TrustPin.shared.setLogLevel(TrustPinLogLevel.debug);
// Create a configuration with your credentials
const config = TrustPinConfiguration(
organizationId: 'your-org-id',
projectId: 'your-project-id',
publicKey: 'LS0tLS1CRUdJTi...', // Your Base64 public key
mode: TrustPinMode.strict, // Use strict mode for production
);
// Initialize the shared instance
await TrustPin.shared.setup(config);
}
For self-hosted configurations, pass a custom URL:
final config = TrustPinConfiguration(
organizationId: 'your-org-id',
projectId: 'your-project-id',
publicKey: 'LS0tLS1CRUdJTi...',
configurationURL: Uri.parse('https://your-server.com/pins.jws'),
);
await TrustPin.shared.setup(config);
Load configuration from a bundled JSON asset
Instead of hard-coding credentials, you can ship a trustpin.json asset and
load it at runtime. The schema matches the native Android SDK, so the same
file works across platforms.
Add the file to your project (for example at the project root) and declare it
in your pubspec.yaml:
flutter:
assets:
- trustpin.json
trustpin.json:
{
"organization_id": "your-org-id",
"project_id": "your-project-id",
"public_key": "LS0tLS1CRUdJTi...",
"mode": "strict",
"configuration_url": "https://your-server.com/pins.jws"
}
| Field | Required | Notes |
|---|---|---|
organization_id |
yes | Non-empty string |
project_id |
yes | Non-empty string |
public_key |
yes | Base64-encoded verification key |
mode |
no | "strict" (default) or "permissive" |
configuration_url |
no | HTTPS URL for self-hosted configs; empty treated as unset |
Then load it:
final config = await TrustPinConfiguration.fromAssets();
await TrustPin.shared.setup(config);
// Or with a custom asset path:
final config = await TrustPinConfiguration.fromAssets(
assetPath: 'config/trustpin-prod.json',
);
Missing, malformed, or invalid assets throw [TrustPinException] with code
INVALID_PROJECT_CONFIG.
3. Validate a Connection #
The recommended workflow is a single call to validateConnection. The
platform composes the certificate fetch and pin verification inside one
channel call, so the certificate never enters the Dart isolate and the
timeout bounds the whole operation:
Future<void> checkServer(String host) async {
try {
await TrustPin.shared.validateConnection(
host,
timeout: const Duration(seconds: 5),
);
print('Connection is allowed by the configured pins.');
} on TrustPinException catch (e) {
print('Validation failed: ${e.code} - ${e.message}');
}
}
If you need the leaf certificate for diagnostics or a custom flow, the
two-step fetchCertificate / verify pair is still available, but both are
deprecated in favor of validateConnection and will be removed in a
future major release:
// ignore: deprecated_member_use
final pem = await TrustPin.shared.fetchCertificate(host);
// ignore: deprecated_member_use
await TrustPin.shared.verify(host, pem);
Advanced Usage #
Integration with Dio #
The SDK provides a built-in TrustPinDioInterceptor for seamless Dio integration:
import 'package:dio/dio.dart';
import 'package:trustpin_sdk/trustpin_sdk.dart';
final dio = Dio();
dio.interceptors.add(TrustPinDioInterceptor());
// All HTTPS requests now have automatic certificate pinning
try {
final response = await dio.get('https://api.example.com/data');
print('Request successful: ${response.statusCode}');
} on DioException catch (e) {
if (e.error is TrustPinException) {
final trustPinError = e.error as TrustPinException;
print('Pinning failed: ${trustPinError.code}');
}
}
The interceptor automatically:
- Calls
validateConnectionon the platform, which fetches the leaf certificate and verifies it against configured pins in a single hop. - Blocks requests when the connection does not match a configured pin.
Integration with http package #
The SDK provides TrustPinHttpClient that wraps the standard http.Client:
import 'package:http/http.dart' as http;
import 'package:trustpin_sdk/trustpin_sdk.dart';
// Create a TrustPin-enabled HTTP client
final client = TrustPinHttpClient.create();
// Or wrap an existing client
final client = TrustPinHttpClient(http.Client());
// Use it like a normal http.Client
final response = await client.get(Uri.parse('https://api.example.com/data'));
// Clean up when done
client.close();
Multiple Instances #
Libraries or multi-tenant apps can use named instances to maintain independent pinning configurations without conflicts:
// Create a named instance for your library
final pin = TrustPin.instance('com.mylib.networking');
await pin.setup(myLibConfig);
// Use the named instance with interceptors
dio.interceptors.add(TrustPinDioInterceptor(instance: pin));
final client = TrustPinHttpClient.create(instance: pin);
Calling TrustPin.instance('id') multiple times with the same ID returns
the same instance.
Manual Certificate Verification #
If you already have the PEM certificate (e.g., from your own TLS implementation):
const pemCertificate = '''
-----BEGIN CERTIFICATE-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END CERTIFICATE-----
''';
try {
await TrustPin.shared.verify('api.example.com', pemCertificate);
print('Certificate is valid!');
} on TrustPinException catch (e) {
print('Verification failed: ${e.code}');
}
Logging #
// Debug logging for development
await TrustPin.shared.setLogLevel(TrustPinLogLevel.debug);
// Minimal logging for production
await TrustPin.shared.setLogLevel(TrustPinLogLevel.error);
// Disable all logging
await TrustPin.shared.setLogLevel(TrustPinLogLevel.none);
API Reference #
TrustPin #
| Member | Description |
|---|---|
TrustPin.shared |
The shared (default) instance for most apps |
TrustPin.instance(id) |
Returns a named instance (for libraries / multi-tenant) |
setup(configuration) |
Initialize the instance with a [TrustPinConfiguration] |
validateConnection(host, {port?, timeout?}) |
Atomic fetch-and-verify. Recommended entry point for cert-pinned HTTPS. |
setLogLevel(level) |
Set logging verbosity |
verify(domain, certificate) |
Deprecated. Use validateConnection. Retained for diagnostic flows. |
fetchCertificate(host, {port?, timeout?}) |
Deprecated. Use validateConnection. Retained for diagnostic flows that need the PEM. |
TrustPinConfiguration #
| Property | Type | Description |
|---|---|---|
organizationId |
String |
Your organization identifier (required) |
projectId |
String |
Your project identifier (required) |
publicKey |
String |
Base64-encoded public key issued by the TrustPin dashboard (required) |
configurationURL |
Uri? |
Optional override for the configuration source (self-hosted setups only) |
mode |
TrustPinMode |
Pinning mode (default: strict) |
TrustPinMode #
| Value | Description |
|---|---|
strict |
Throws errors for unregistered domains (recommended for production) |
permissive |
Allows unregistered domains to bypass pinning (development/testing) |
TrustPinLogLevel #
| Value | Description |
|---|---|
none |
No logging output |
error |
Only error messages |
info |
Errors and informational messages |
debug |
All messages including detailed debug information |
HTTP Interceptors #
| Class | Description |
|---|---|
TrustPinDioInterceptor({instance?}) |
Certificate pinning interceptor for Dio |
TrustPinHttpClient({instance?}) |
Certificate pinning wrapper for http.Client |
Full API documentation: trustpin-cloud.github.io/flutter.sdk
Error Handling #
All TrustPin operations throw TrustPinException on failure. Use the convenience getters to check for specific error types:
try {
await TrustPin.shared.verify('api.example.com', certificate);
} on TrustPinException catch (e) {
if (e.isDomainNotRegistered) {
// Domain not configured for pinning (strict mode only)
} else if (e.isPinsMismatch) {
// Certificate doesn't match any configured pins
} else if (e.isAllPinsExpired) {
// All pins for this domain have expired
} else if (e.isInvalidServerCert) {
// Certificate format is invalid
}
}
| Error Code | Getter | Description |
|---|---|---|
INVALID_PROJECT_CONFIG |
isInvalidProjectConfig |
Invalid or missing credentials |
ERROR_FETCHING_PINNING_INFO |
isErrorFetchingPinningInfo |
Failed to fetch pinning configuration |
INVALID_SERVER_CERT |
isInvalidServerCert |
Invalid certificate format |
PINS_MISMATCH |
isPinsMismatch |
Certificate doesn't match configured pins |
ALL_PINS_EXPIRED |
isAllPinsExpired |
All pins for the domain have expired |
DOMAIN_NOT_REGISTERED |
isDomainNotRegistered |
Domain not configured (strict mode) |
CONFIGURATION_VALIDATION_FAILED |
isConfigurationValidationFailed |
Configuration validation failed |
FETCH_CERTIFICATE_TIMEOUT |
isFetchCertificateTimeout |
fetchCertificate exceeded its timeout |
Example App #
The sample_app/ directory contains a complete example application demonstrating:
- SDK initialization with
TrustPin.shared.setup() - Certificate fetching with
TrustPin.shared.fetchCertificate() - Connection testing with
TrustPinHttpClient - Error handling and logging
Run the example:
cd sample_app
flutter run
Secure your Flutter apps with TrustPin SSL Certificate Pinning