Overview
Add certificate or public key pin checks to the actual TLS connection before sending HTTP data to configured hosts.
flutter_ssl_pinning_client is an HTTP client for applications that need an additional check on the identity of their API server. You supply verified certificate or public key fingerprints, and the client compares them with the actual connection before sending your request.
Installation
Add the package to your Flutter project.
flutter pub add flutter_ssl_pinning_client:^2.0.0Version 2.0.0 requires Dart 3.5 and Flutter 3.24 or later. Review the migration notes if you used 1.x.
Quick Start
Replace the example host and both placeholder pins with independently verified values. The placeholders intentionally reject connections.
import 'package:flutter_ssl_pinning_client/flutter_ssl_pinning_client.dart';
Future<void> main() async {
final client = SslPinningHttpClient(
config: SslPinningConfig(
domainConfigs: {
'api.example.com': const DomainPinConfig(
domain: 'api.example.com',
allowedSHA256Pins: {
'REPLACE_WITH_VERIFIED_PRIMARY_PIN',
'REPLACE_WITH_VERIFIED_BACKUP_PIN',
},
),
},
),
);
try {
final response = await client.get(
Uri.parse('https://api.example.com/account'),
);
print('Status: ' + response.statusCode.toString());
} finally {
client.close();
}
}A matching pin does not replace ordinary HTTPS validation. Invalid or untrusted certificates are still rejected.
Configuration
Use exact domain rules where possible. A wildcard such as *.example.com matches one label, not the apex domain or deeper subdomains. Exact matches take precedence.
| Option | Behavior |
|---|---|
domainConfigs | Only configured hosts receive pin checks. Other HTTPS hosts use ordinary TLS validation. |
mode | Strict by default. Report mode records a mismatch but allows a normally valid TLS connection. |
connectionTimeout | 15 seconds by default. It is not a timeout for the entire response body. |
securityContext | Explicit trust and client certificate configuration. Keep production trust restrictive. |
Pin Rotation
Ship a primary and backup pin before the server changes its certificate or key. Replace the set only after authenticating the new configuration.
config.updatePinsForDomain('api.example.com', {
'VERIFIED_CURRENT_PIN',
'VERIFIED_NEXT_PIN',
});New requests use a fresh connection and the updated pins. An already verified request in flight is not revoked. The package does not fetch, sign, persist or protect remote configuration against rollback.
Security Model
- Establish TLS with ordinary trust, hostname and certificate validity checks.
- Read the leaf certificate on that same connection and compare its certificate or SPKI fingerprint.
- In strict mode, reject a mismatch before handing the connection to the HTTP client.
HTTP is rejected. Redirect responses are returned without automatically following them. Path bypasses and custom HTTP transports are not supported. Report mode never authorizes an invalid TLS certificate.
Pin Formats
| Value | What is hashed |
|---|---|
| 64 character hex or colon separated hex | Complete leaf certificate DER |
| Plain base64 | Complete leaf certificate DER |
sha256/<base64> | Leaf SubjectPublicKeyInfo DER |
sha256/<64 hex characters> | Legacy certificate format |
Base64 is case sensitive. Certificate renewal changes a certificate pin. An SPKI pin can survive renewal if the server keeps the same key. Only leaf pins are supported.
Known Limitations
Pinning covers requests sent through this client only. It does not secure WebViews or other network clients. Simulator checks are not a security certification. Plan backup pins and validate your real API before production use.
Version 2.0.0 uses direct connections without pooling or HTTP proxy support. Consume or cancel response streams and close your client. Physical device testing remains separate from the simulator results below.
API Reference
Explore the public classes, methods and constructors for version 2.0.0.
Open versioned API referenceExample & Tests
The SSL Pinning Lab runs a local HTTPS server inside the example app. It tests certificate pins, SPKI pins, wrong and empty pins, backup pins, report mode, untrusted certificates and redirect handling without using a public service.
Verified using Flutter 3.44.4. A rejected request must produce the expected error and send zero HTTP requests to the local server. This is not a claim of complete security.
The expanded simulator lab is currently local and has not yet been pushed to GitHub. The repository link contains the published package source and its smaller usage example.
git clone https://github.com/lekthedeveloper/flutter_ssl_pinning_client.git
cd flutter_ssl_pinning_client
flutter pub get
flutter testFrequently Asked Questions
Does this work on Flutter Web?
No. This package uses Dart IO sockets and cannot enforce certificate pinning in a browser.
Why does a request fail even when the pin matches?
The certificate must also pass normal trust, hostname and expiry checks. A matching pin never overrides invalid TLS. Check your configured host, pin format, certificate chain and error type.
How should I obtain production pins?
Verify fingerprints through an independent authenticated channel. The helper is useful during development but observing a certificate over the network is not independent proof of authenticity. Always plan a backup pin.