iOS / macOS SDK
Integrate TrustPin into your Apple platform application with native certificate pinning protection.
Current version: TrustPinKit 5.0.0
Platform Requirements
| Platform | Minimum Version |
|---|---|
| iOS | 13.0+ |
| macOS | 13.0+ |
| watchOS | 7.0+ |
| tvOS | 13.0+ |
| Mac Catalyst | 13.0+ |
| visionOS | 2.0+ |
Swift Version: 5.5+ (async/await is required)
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/swift.sdk - Select version 5.0.0 or later (Up to Next Major).
Package.swift
For command-line projects:
dependencies: [
.package(url: "https://github.com/trustpin-cloud/swift.sdk", from: "5.0.0")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "TrustPinKit", package: "swift.sdk")
]
)
]CocoaPods
Add to your Podfile:
pod 'TrustPinKit', '~> 5.0'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
Ship a TrustPin-Info.plist in your app bundle and load it with TrustPinConfiguration.fromPlist(). Credentials stay out of source.
The plist must contain the following keys:
| Key | Type | Required | Notes |
|---|---|---|---|
OrganizationId | String | Yes | Non-empty |
ProjectId | String | Yes | Non-empty |
PublicKey | String | Yes | Base64-encoded ECDSA P-256 public key |
Mode | String | No | "strict" (default) or "permissive", lowercase |
ConfigurationURL | String | No | Must be HTTPS. Overrides the default CDN endpoint |
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 {
let config = try TrustPinConfiguration.fromPlist()
try await TrustPin.setup(config)
print("TrustPin initialized")
} catch {
print("TrustPin setup failed: \(error)")
}
}
return true
}
}TrustPinConfiguration.fromPlist() throws TrustPinErrors.invalidProjectConfig if any required key is missing or malformed.
Per-environment plists
Point the factory at a different bundle or filename to ship different credentials per scheme:
#if DEBUG
let config = try TrustPinConfiguration.fromPlist(fileName: "TrustPin-Info-Debug.plist")
#else
let config = try TrustPinConfiguration.fromPlist(fileName: "TrustPin-Info.plist")
#endif
try await TrustPin.setup(config)Integration Approaches
TrustPin offers three integration methods:
| Approach | Best For | Setup Complexity |
|---|---|---|
| URLSessionDelegate (Recommended) | Most applications, precise control | 🟢 Low |
| System-Wide URLProtocol | Third-party library protection, legacy code | 🟡 Medium |
| Helper Methods | One-off requests, explicit control | 🟠 High |
URLSessionDelegate (Recommended)
Bind a URLSession to a TrustPin-backed delegate produced by the SDK:
import TrustPinKit
class NetworkManager {
private lazy var session: URLSession = {
let delegate = TrustPin.makeURLSessionDelegate()
return URLSession(
configuration: .default,
delegate: delegate,
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
}
}System-Wide URLProtocol
Register TrustPinURLProtocol to apply pinning to every request that goes through the default URL Loading System — useful when third-party libraries don’t expose a URLSession you control.
You can either register automatically during setup, or register/unregister manually:
let config = try TrustPinConfiguration.fromPlist()
try await TrustPin.setup(config, autoRegisterURLProtocol: true)
// Or manage registration explicitly:
TrustPin.registerURLProtocol()
TrustPin.unregisterURLProtocol()Helper Methods
TrustPinURLProtocol exposes convenience helpers for individual requests:
let (data, _) = try await TrustPinURLProtocol.data(from: url)
let (fileURL, _) = try await TrustPinURLProtocol.download(for: request)Manual Verification
For custom transports or one-off checks, validate a domain/certificate pair directly:
try await TrustPin.verify(
domain: "api.example.com",
certificate: pemEncodedCertificate
)Named Instances (Multi-Tenant)
If your app talks to multiple TrustPin projects (for example, separate consumer and admin backends), ship one plist per project and create independent instances:
let customerConfig = try TrustPinConfiguration.fromPlist(fileName: "TrustPin-Customer.plist")
let customerApi = try TrustPin.instance(id: "customer-api")
try await customerApi.setup(customerConfig)
let adminConfig = try TrustPinConfiguration.fromPlist(fileName: "TrustPin-Admin.plist")
let adminApi = try TrustPin.instance(id: "admin-api")
try await adminApi.setup(adminConfig)The id must be non-empty and not equal to "default"; otherwise TrustPinErrors.invalidProjectConfig is thrown. Repeated calls with the same id return the same instance.
Logging
Set the desired verbosity before calling setup() to capture initialization logs:
await TrustPin.set(logLevel: .debug)Available levels: .none, .error, .info, .debug.
Error Handling
All SDK errors are cases of TrustPinErrors:
do {
try await TrustPin.setup(config)
} catch TrustPinErrors.invalidProjectConfig {
// Bad credentials or invalid configuration
} catch TrustPinErrors.errorFetchingPinningInfo {
// Network failure while loading the configuration
} catch TrustPinErrors.configurationValidationFailed {
// JWS signature didn't verify against the project's public key
} catch TrustPinErrors.domainNotRegistered {
// Strict mode and the host isn't in the configuration
} catch TrustPinErrors.pinsMismatch {
// Server certificate doesn't match any active pin
} catch TrustPinErrors.allPinsExpired {
// Configuration is stale — rotate pins in the dashboard
} catch TrustPinErrors.invalidServerCert {
// Server returned an unparseable certificate
}Best Practices
Setup & Initialization
- Call
TrustPin.setup()once during app launch. Subsequent calls return immediately. - Set the log level before
setup()to capture initialization output. - Handle setup errors gracefully — don’t block app launch.
- Don’t call
setup()concurrently from multiple tasks for the same instance.
Security
- Use
.strictmode in production. - Prefer SPKI pinning; rotate pins in the dashboard before they expire.
- Monitor pin validation failures via logging or analytics.
- Keep credentials outside source control —
TrustPinConfiguration.fromPlist()reads from a bundled plist. - Use HTTPS for all pinned domains.
Performance
- Reuse
URLSessioninstances rather than creating a new one per request. - Configuration is cached for 10 minutes; the SDK refreshes automatically.
- Use
.erroror.nonelog levels in production.
Complete Documentation
For the full API reference, including every method signature, integration examples (Alamofire, third-party clients), and advanced configuration, visit:
Resources
- Repository: github.com/trustpin-cloud/swift.sdk
- API Reference: trustpin-cloud.github.io/swift.sdk
- Dashboard: app.trustpin.cloud
- Support: support@trustpin.cloud