Skip to main content

Command Palette

Search for a command to run...

🔐 SSL Pinning in React Native (iOS + Android) – A Practical Implementation

Updated
•4 min read•View as Markdown
🔐 SSL Pinning in React Native (iOS + Android) – A Practical Implementation
A
Dedicated and efficient full stack developer with 8+ years of experience in application layers, presentation layers, and databases. Developed multiple web applications as a full stack developer to process, analyze, and render data visually. Worked on query optimization for the betterment of existing sections.

When we build mobile apps, we usually call APIs over HTTPS and assume everything is secure.

But here’s the reality:
Even with HTTPS, your app can still be vulnerable to Man-in-the-Middle (MITM) attacks where an attacker intercepts your network traffic.

That’s where SSL Pinning comes in.

SSL Pinning ensures that your mobile app only talks to your trusted server and rejects any other certificate, even if it appears valid.

Recently, I implemented SSL Pinning in a React Native application for both iOS and Android, and I wanted to share the approach in a simple way.

🧠 What is SSL Pinning (Simple Explanation)

Normally when your app connects to a server:

  1. The server sends an SSL certificate

  2. The device checks if the certificate is issued by a trusted authority

  3. If valid → connection continues

But attackers can sometimes install fake certificates on compromised devices.

With SSL Pinning, your app also checks:

“Does this certificate match the one I trust?”

If it doesn't match, the connection is blocked immediately.

No API call. No data leak.

🧰 Library Used

For React Native, I used:

react-native-ssl-public-key-pinning

It supports both iOS and Android and pins the public key instead of the entire certificate (which is easier to rotate).

Install it:

npm install react-native-ssl-public-key-pinning

🔎 Step 1: Get the Public Key Hash

First, you need your server’s SHA256 public key hash.

Use this tool: https://www.ssllabs.com/ssltest/

Steps:

  1. Enter your API base URL

  2. Run the test

  3. Copy the SHA256 public key hash

You should keep two keys:

  • Primary key

  • Backup key (for certificate rotation)

⚙️ Step 2: Initialize SSL Pinning in App Startup

I initialize SSL pinning when the app launches.

In App.tsx

useEffect(() => {
  const initializeSecurityTest = async () => {
    try {
      await initRemoteConfig();

      const flags = getRemoteFlags();
      console.log('Remote Config Flags:', flags);

      if (flags.enableSslPinning) {
        const success = await initializeSslPinningLib(flags);

        if (success) {
          console.log('SSL pinning successfully initialized');
        } else {
          console.log('Failed to initialize SSL pinning');
        }
      } else {
        disableSslPinning?.();
        console.log('SSL pinning disabled by remote flag');
      }
    } catch (err) {
      console.warn('Security initialization error', err);
    }
  };

  initializeSecurityTest();
}, []);

🚨 Listening for SSL Pinning Errors

If a certificate mismatch happens, we detect it immediately.

useEffect(() => {
  const subscription = addSslPinningErrorListener((error) => {
    console.log('SSL Pinning Error:', error);
    setSslAlert(true);
  });

  return () => {
    subscription.remove();
  };
}, []);

🧩 Step 3: Create a Utility for SSL Pinning

Create a helper file:

sslpinning.js

import Config from 'react-native-config';
import {
  initializeSslPinning,
  isSslPinningAvailable,
} from 'react-native-ssl-public-key-pinning';

export const initializeSslPinningLib = async (flags) => {
  try {
    if (!isSslPinningAvailable()) {
      console.warn('[SSL Pinning] Not available');
      return false;
    }

    const hostname = flags.ssl_pinning_hostname;
    const primaryKey = flags.ssl_pinning_primary_public_key;
    const backupKey = flags.ssl_pinning_backup_public_key;

    const sslPinningConfig = {
      [hostname]: {
        includeSubdomains: false,
        publicKeyHashes: [primaryKey, backupKey],
      },
    };

    await initializeSslPinning(sslPinningConfig);

    console.log(`[SSL Pinning] Initialized for ${hostname}`);

    return true;
  } catch (error) {
    console.error('[SSL Pinning] Initialization failed:', error);
    return false;
  }
};

🧪 Step 4: Testing SSL Pinning

When testing, verify these scenarios:

✅ Valid Public Key

API calls should work normally.

❌ Invalid Public Key

Connection should fail immediately.

Your app must not allow API calls if the certificate does not match the pinned key.

☁️ Why We Used Remote Config

Instead of hardcoding keys in the app, we used Firebase Remote Config.

Benefits:

• Enable/disable SSL pinning remotely
• Update keys without releasing a new app
• Quickly react if something breaks in production

This gives us flexibility without sacrificing security.

🔒 Security Best Practices

A few important lessons from this implementation:

✅ Always keep a backup key
✅ Avoid hardcoding secrets directly in the app
✅ Use remote config for flexibility
✅ Handle SSL pinning errors gracefully
✅ Test certificate rotation scenarios

💡 Final Thoughts

SSL Pinning adds an extra layer of trust between your mobile app and backend.

It’s not always implemented in many apps, but for apps handling:

  • Payments

  • User data

  • Authentication

  • Financial information

…it’s highly recommended.

Security is never about one solution, it's about layers of protection.


Thanks a lot for reading till the end 🙏 You can contact me in case if you need any assistance:

Email: atul19251@gmail.com

LinkedIn:https://www.linkedin.com/in/atul-kumar-singh-673357102/

More from this blog

D

Dev Station

29 posts

Dedicated and efficient full stack developer with 6+ years of experience in application layers, presentation layers, and databases 🙂