iOS SDK
Integrate TrustPin into your iOS application with comprehensive certificate pinning protection.
Platform Requirements
| Platform | Minimum Version | Support |
|---|---|---|
| iOS | 13.0+ | ✅ |
| macOS | 13.0+ | ✅ |
| watchOS | 7.0+ | ✅ |
| tvOS | 13.0+ | ✅ |
| visionOS | 2.0+ | ✅ |
Swift Version: 5.5+ (requires async/await support)
Installation
Swift Package Manager (Recommended)
Add TrustPin to your project in Xcode:
- Go to File → Add Package Dependencies
- Enter the repository URL:
https://github.com/trustpin-cloud/TrustPin-Swift.binary - Select version 2.0.0 or later
Package.swift
For command-line projects:
dependencies: [
.package(url: "https://github.com/trustpin-cloud/TrustPin-Swift.binary", from: "2.0.0")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "TrustPinKit", package: "TrustPin-Swift")
]
)
]CocoaPods
Add to your Podfile:
pod 'TrustPinKit'Then run:
pod installQuick 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 app’s initialization (e.g., AppDelegate or @main struct):
import TrustPinKit
class AppDelegate: UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Task {
do {
try await TrustPin.setup(
organizationId: "your-org-id",
projectId: "your-project-id",
publicKey: "your-base64-public-key",
mode: .strict
)
print("TrustPin initialized")
} catch {
print("TrustPin setup failed: \(error)")
}
}
return true
}
}SwiftUI Apps
import SwiftUI
import TrustPinKit
@main
struct MyApp: App {
init() {
Task {
try? await TrustPin.setup(
organizationId: "your-org-id",
projectId: "your-project-id",
publicKey: "your-base64-public-key",
mode: .strict
)
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}3. Make Network Requests
After setup, all URLSession requests automatically use certificate pinning:
// URLSession.shared is automatically protected
let url = URL(string: "https://api.example.com/data")!
let (data, _) = try await URLSession.shared.data(from: url)Integration Approaches
TrustPin offers three integration methods:
| Approach | Best For | Complexity |
|---|---|---|
| System-Wide URLProtocol (Default) | Most apps | 🟢 Minimal |
| URLSessionDelegate | Custom URLSession instances | 🟡 Medium |
| Helper Methods | Explicit control | 🟠 Per-request |
System-Wide URLProtocol (Recommended)
Automatically protects all URLSession requests across your entire application after setup:
// Setup once during app initialization
try await TrustPin.setup(
organizationId: "your-org-id",
projectId: "your-project-id",
publicKey: "your-base64-public-key",
mode: .strict
// autoRegisterURLProtocol: true (enabled by default)
)
// All URLSession requests are now automatically protected
let (data, _) = try await URLSession.shared.data(from: url)
// Custom URLSession instances are also protected
let session = URLSession(configuration: .ephemeral)
let (data2, _) = try await session.data(from: url)
// Third-party networking libraries using URLSession are also protected automatically!How it works: TrustPin registers a custom URLProtocol subclass that intercepts all URLSession requests, validates certificates against your configured pins, and either allows or blocks the connection based on the validation result.
Manual Control
For advanced scenarios:
// Disable auto-registration during setup
try await TrustPin.setup(
organizationId: "your-org-id",
projectId: "your-project-id",
publicKey: "your-base64-public-key",
mode: .strict,
autoRegisterURLProtocol: false
)
// Enable/disable manually
TrustPin.registerURLProtocol() // Enable protection
TrustPin.unregisterURLProtocol() // Disable protectionURLSessionDelegate
For granular control over specific URLSession instances:
import TrustPinKit
class NetworkManager {
private let trustPinDelegate = TrustPinURLSessionDelegate()
private lazy var session = URLSession(
configuration: .default,
delegate: trustPinDelegate,
delegateQueue: nil
)
func fetchData() async throws -> Data {
let url = URL(string: "https://api.example.com/data")!
let (data, _) = try await session.data(from: url)
return data
}
}Helper Methods
Explicit control for individual requests:
import TrustPinKit
// Async/await
let (data, _) = try await TrustPinURLProtocol.data(from: url)
// Completion handler
let task = TrustPinURLProtocol.dataTask(with: url) { data, response, error in
// Handle response
}
task.resume()
// Create custom session with pinning
let session = URLSession.trustPinSession(configuration: .ephemeral)Configuration
Pinning Modes
Strict Mode
Rejects connections to unregistered domains:
try await TrustPin.setup(
organizationId: "your-org-id",
projectId: "your-project-id",
publicKey: "your-base64-public-key",
mode: .strict // Recommended for production
)Permissive Mode
Allows unregistered domains to bypass pinning:
try await TrustPin.setup(
organizationId: "your-org-id",
projectId: "your-project-id",
publicKey: "your-base64-public-key",
mode: .permissive // For development/testing
)Logging
Enable debug logging for troubleshooting:
// Set log level before setup
await TrustPin.set(logLevel: .debug)
// Available levels:
// .none - No logging (production)
// .error - Errors only
// .info - Errors + informational messages
// .debug - All messages (development)Error Handling
TrustPin provides detailed error types:
import TrustPinKit
do {
try await TrustPin.verify(domain: "api.example.com", certificate: pemCert)
print("Certificate is valid")
} catch TrustPinErrors.domainNotRegistered {
// Domain not configured (strict mode only)
print("Domain not registered")
} catch TrustPinErrors.pinsMismatch {
// Certificate doesn't match pins - possible MITM attack
print("SECURITY: Certificate mismatch")
} catch TrustPinErrors.allPinsExpired {
// All pins expired for this domain
print("Pins expired")
} catch TrustPinErrors.invalidServerCert {
// Invalid certificate format
print("Invalid certificate")
} catch TrustPinErrors.invalidProjectConfig {
// Setup configuration invalid
print("Configuration error")
} catch TrustPinErrors.errorFetchingPinningInfo {
// Network error fetching configuration
print("Network error")
} catch TrustPinErrors.configurationValidationFailed {
// Signature validation failed
print("Signature validation failed")
} catch {
print("Unexpected error: \(error)")
}Best Practices
Setup & Initialization
- Call
TrustPin.setup()only once during app launch - Handle setup errors gracefully - don’t block app launch
- Set log level before setup for complete logging
- Never call setup concurrently
- Use Task/async context in synchronous lifecycle methods
Security
- Use
.strictmode in production - Rotate pins before expiration
- Monitor pin validation failures
- Keep credentials secure (use environment variables)
- Use HTTPS for all pinned domains
Performance
- Cache is handled automatically (10-minute TTL)
- Reuse URLSession instances
- Use
.erroror.nonelog level in production - Initialize early to avoid delays
Development Workflow
- Start with
.permissivemode - Test all endpoints with pinning enabled
- Validate pin configurations in staging
- Switch to
.strictmode for production - Use
.debuglogging to troubleshoot
Integration with Third-Party Libraries
Alamofire
import Alamofire
import TrustPinKit
class TrustPinAlamofireDelegate: TrustPinURLSessionDelegate, SessionDelegate {
// TrustPinURLSessionDelegate handles validation
}
let delegate = TrustPinAlamofireDelegate()
let session = Session(
configuration: .default,
delegate: delegate
)
// Use session for requests
let response = try await session.request("https://api.example.com/data")
.validate()
.serializingData()
.valueTroubleshooting
Setup Fails with invalidProjectConfig
- Verify credentials in TrustPin Dashboard
- Check for whitespace in credentials
- Ensure public key is base64-encoded
- Avoid concurrent setup calls
Certificate Verification Fails
- Confirm domain is registered in dashboard
- Verify certificate format (PEM-encoded)
- Check pin expiration dates
- Test with
.permissivemode first
Network Requests Hang
- Verify correct URLSession delegate
- Check for retain cycles
- Test network connectivity
- Ensure URLProtocol is registered
System-Wide Pinning Not Working
- Confirm
autoRegisterURLProtocol: true(default) - Test with HTTPS URLs only
- Verify URLProtocol not unregistered elsewhere
- Manually call
TrustPin.registerURLProtocol()
API Reference
Core Classes
TrustPin- Main SDK interfaceTrustPinMode- Pinning modes (.strict,.permissive)TrustPinURLSessionDelegate- URLSession delegateTrustPinURLProtocol- System-wide pinning (iOS 13.0+)TrustPinErrors- Error typesTrustPinLogLevel- Logging configuration
Key Methods
// Setup
static func setup(
organizationId: String,
projectId: String,
publicKey: String,
mode: TrustPinMode = .strict,
autoRegisterURLProtocol: Bool = true
) async throws
// Manual verification
static func verify(domain: String, certificate: String) async throws
// URLProtocol control
static func registerURLProtocol()
static func unregisterURLProtocol()
// Logging
static func set(logLevel: TrustPinLogLevel) asyncProduction Deployment
Production Configuration
1. Set Production Mode
import TrustPinKit
// In production build
try await TrustPin.setup(
organizationId: ProcessInfo.processInfo.environment["TRUSTPIN_ORG_ID"]!,
projectId: ProcessInfo.processInfo.environment["TRUSTPIN_PROJECT_ID"]!,
publicKey: ProcessInfo.processInfo.environment["TRUSTPIN_PUBLIC_KEY"]!,
mode: .strict // Always strict in production
)
// Set minimal logging
await TrustPin.set(logLevel: .error)2. Xcode Build Configuration
Add environment variables to your Xcode scheme:
- Product → Scheme → Edit Scheme
- Select Run → Arguments tab
- Add Environment Variables:
TRUSTPIN_ORG_ID: Your organization IDTRUSTPIN_PROJECT_ID: Your project IDTRUSTPIN_PUBLIC_KEY: Your public key
3. App Store Submission
Before submitting to App Store:
- Test on physical devices (not just simulator)
- Verify certificate pinning works on cellular and WiFi
- Test with TestFlight beta before production release
- Document TrustPin usage in App Privacy details
- Include “Uses TrustPin™ technology” attribution
Info.plist Configuration
Ensure your Info.plist allows network access to TrustPin CDN:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>cdn.trustpin.cloud</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
</dict>
</dict>
</dict>Resources
- Repository: github.com/trustpin-cloud/TrustPin-Swift.binary
- API Docs: trustpin-cloud.github.io/TrustPin-Swift
- Dashboard: app.trustpin.cloud
- Support: support@trustpin.cloud