Recently, I implemented SSL pinning in one of my React Native applications to improve the security of API communication. Since mobile apps constantly interact with backend servers, protecting those requests from attacks is extremely important.
In this article, I'll share why SSL pinning is important and how I implemented it in my React Native app.
Why SSL Pinning Is Important

Normally, when an app communicates with a server using HTTPS, the SSL certificate is validated by the device's trusted Certificate Authority (CA).
While HTTPS already provides a good level of security, there is still a risk of Man-in-the-Middle (MITM) attacks. In such attacks, a malicious actor intercepts the communication between the mobile app and the server.
SSL pinning adds an extra layer of security by ensuring the app only trusts a specific certificate or public key, rather than any certificate issued by a trusted CA.
This means that even if someone installs a malicious certificate on the device, the app will refuse the connection.
Why I Used Public Key Pinning
Instead of pinning the entire certificate, I used public key pinning using the library:
react-native-ssl-public-key-pinning
Public key pinning is more flexible because:
• Certificates can expire or rotate • The public key often remains the same • It reduces maintenance when certificates change
This library allows us to securely make API requests while validating the server's certificate.
Step 1: Install the Library
First, install the package:
npm install react-native-ssl-public-key-pinningor
yarn add react-native-ssl-pinningThen install iOS dependencies:
cd ios
pod installStep 2: Get the Public Key Hash
Next, you need the SHA256 public key hash of your server certificate.
Run this single command — it connects to your server and extracts the SHA-256 hash of the public key in one shot:
openssl s_client -connect api.yourdomain.com:443 -servername api.yourdomain.com < /dev/null 2>/dev/null \
| openssl x509 -pubkey -noout \
| openssl pkey -pubin -outform DER \
| openssl dgst -sha256 -binary \
| base64This command returns a base64 encoded SHA256 hash of the public key.
Example output:
AbCdEfGhIjKlMnOpQrStUvWxYz1234567890abcdef=
Step 3: Configure SSL Public Key Pinning
In your React Native app, initialize the pinning configuration.
Example:
import { initializeSslPinning } from 'react-native-ssl-public-key-pinning';
initializeSslPinning({
'yourapi.com': {
includeSubdomains: true,
publicKeyHashes: [
'AbCdEfGhIjKlMnOpQrStUvWxYz1234567890abcdef=',
'backupPublicKeyHashHere'
],
},
});It is recommended to include at least two keys:
- Primary key
- Backup key
This prevents the app from breaking when certificates rotate.
How to get the backup hash (critical — prevents outage)
The backup pin is your next certificate's public key or your CA's public key.
Option A — Pin the Intermediate CA (best practice):
# Get the full chain and extract intermediate cert
openssl s_client -connect api.yourdomain.com:443 -servername api.yourdomain.com -showcerts < /dev/null 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{i++} i==2{print}' \
| openssl x509 -pubkey -noout \
| openssl pkey -pubin -outform DER \
| openssl dgst -sha256 -binary \
| base64The i==2 selects the intermediate CA cert (second in chain). Its public key almost never changes across renewals — this is the safest backup pin.
Option B — Generate your next private key now and pre-compute its hash:
openssl genrsa 2048 | openssl rsa -outform DER -pubout 2>/dev/null \
| openssl dgst -sha256 -binary | base64Step 4: Testing the Implementation

To verify the implementation, I tested the app using proxy tools such as Charles Proxy
Run the App Normally, Trigger an API call. API should work normally
Open Charles, Enable Proxy → macOS Proxy → Then start recording
Enable SSL Proxying, Go to Proxy → SSL Proxying Settings → Enable SSL Proxying → Add your domain:
Host: live.venu-iq.com
Port: 443Install Charles Root Certificate
In Charles:
Help → SSL Proxying → Install Charles Root CertificateThen, in Keychain Access, set:
Charles Proxy CA → Always TrustRun your React Native app again and trigger the same API.
On iOS, the API request failed as expected.
- This confirmed that SSL pinning was successfully blocking intercepted connections.
- When the proxy was disabled, the API worked normally.
This ensured that the app only trusts the pinned public key.
One important rule when using public key pinning is:
Always provide at least two pins (primary + backup).
Otherwise, the app might fail if the certificate changes.
Final Thoughts
Security should always be a priority in mobile development, especially when apps communicate with sensitive backend services.
Implementing SSL public key pinning adds a strong layer of protection against network interception attacks.
If your React Native app communicates with production APIs, I highly recommend considering SSL pinning as part of your security strategy.
Please clap if you liked the post.