npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-ssl-pinning

v0.1.6

Published

SSL certificate pinning for Expo applications. Protect against MITM attacks by validating server certificates against known public key hashes.

Readme

expo-ssl-pinning

SSL Certificate/Public Key Pinning for Expo applications using Expo Native Modules.

Overview

This package provides SSL certificate pinning functionality for Expo apps to protect against Man-in-the-Middle (MITM) attacks by validating server certificates against known public key hashes.

Features

  • iOS Support - SPKI hash validation via URLSession
  • Android Support - Certificate pinning via OkHttp
  • Config Plugin - Automatic build-time configuration injection
  • Multiple Hosts - Configure pinning for multiple domains
  • Backup Keys - Support for multiple hashes per host (recommended for certificate rotation)
  • Zero Runtime Configuration - All configuration happens at build time

Installation

npm install expo-ssl-pinning
# or
yarn add expo-ssl-pinning

Prerequisites

  • Expo SDK 48+ (recommended)
  • EAS Build or Expo Bare workflow
  • Access to native iOS and Android code

Usage

Step 1: Generate SPKI Hashes

You need to generate the SPKI (Subject Public Key Info) hash for your server's certificate.

Option A: If you have the certificate file

openssl x509 -in cert.pem -pubkey -noout | \
openssl pkey -pubin -outform DER | \
openssl dgst -sha256 -binary | \
base64

Option B: If you only have the domain

openssl s_client -connect api.yourdomain.com:443 -servername api.yourdomain.com </dev/null | \
openssl x509 -pubkey -noout | \
openssl pkey -pubin -outform DER | \
openssl dgst -sha256 -binary | \
base64

The output will be a base64-encoded string like: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=

Important: Always generate and pin at least 2 hashes:

  1. Your current certificate's hash (primary)
  2. Your backup/next certificate's hash (backup)

This prevents app lockout during certificate rotation.

Step 2: Configure in app.config.js

Add the plugin to your app.config.js or app.json:

export default {
  expo: {
    // ... other config
    plugins: [
      [
        "expo-ssl-pinning",
        {
          sslPinning: {
            hosts: {
              "api.yourdomain.com": [
                "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", // Primary certificate hash
                "bXNvZGF0YQpkYXRhCmRhdGEK47DEQpj8HBSa5JCeuQeR=", // Backup certificate hash
              ],
              "api2.yourdomain.com": [
                "aW5jbHVkZQpkYXRhCmRhdGEK47DEQpj8HBSa5JCeuQeR=",
                "ZGF0YQpkYXRhCmRhdGEK47DEQpj8HBSa5JCeuQeRkm5N=",
              ],
            },
          },
        },
      ],
    ],
  },
};

Step 3: Build

# For EAS Build
eas build --platform ios
eas build --platform android

# For Expo Prebuild
expo prebuild

Configuration

Plugin Options

{
  sslPinning: {
    hosts: {
      [hostname: string]: string[]  // Array of base64-encoded SHA-256 SPKI hashes
    }
  }
}

Example Configuration

{
  sslPinning: {
    hosts: {
      // Production API
      "api.production.com": [
        "currentCertHash==",
        "backupCertHash=="
      ],
      // Staging API
      "api.staging.com": [
        "stagingCertHash==",
        "stagingBackupHash=="
      ]
    }
  }
}

How It Works

Build Time

  1. The config plugin reads your SSL pinning configuration from app.config.js
  2. iOS: Injects the configuration into Info.plist
  3. Android: Injects the configuration into AndroidManifest.xml as meta-data
  4. Native modules read this configuration on app startup

Runtime

  1. iOS: Uses URLSession delegate to intercept certificate validation
  2. Android: Uses OkHttp CertificatePinner to validate certificates
  3. When your app makes HTTPS requests, the native layer validates the server's public key hash
  4. If the hash matches any configured hash for that host, the connection proceeds
  5. If no match is found, the connection is rejected

API Reference

JavaScript Methods

import * as ExpoSslPinning from "expo-ssl-pinning";

// Check if SSL pinning is enabled
const isEnabled = ExpoSslPinning.isPinningEnabled();

// Get list of pinned hosts (iOS only)
const hosts = ExpoSslPinning.getPinnedHosts();

// Reinitialize pinning (rarely needed)
await ExpoSslPinning.reinitializePinning();

Best Practices

✅ DO

  • Always pin at least 2 hashes per host (primary + backup)
  • Pin only your own backend domains that you control
  • Test pinning in staging before production
  • Monitor certificate expiration dates
  • Have a certificate rotation plan
  • Update backup hash before primary certificate expires

❌ DON'T

  • Never pin third-party services (Firebase, Google, AWS, etc.)
    • They rotate certificates frequently
    • You have no control over their certificate lifecycle
    • Your app will break when they update certificates
  • Don't pin only one hash - you'll lock users out during rotation
  • Don't pin in development - use staging/production only
  • Don't forget to update backup hashes before certificate expiry

Troubleshooting

Certificate Validation Failures

Symptoms: Network requests fail with SSL errors

Solutions:

  1. Verify your SPKI hash is correct - regenerate it
  2. Check that the hostname in your config exactly matches the request URL
  3. Ensure you're using the latest certificate (not an expired one)
  4. Check logs:
    • iOS: Look for "ExpoSslPinning" logs in Xcode console
    • Android: Check Logcat for "ExpoSslPinning" tags

Plugin Not Working

Symptoms: No SSL pinning happening (no errors, no validation)

Solutions:

  1. Run expo prebuild --clean to regenerate native projects
  2. Verify plugin.js exists in the module directory
  3. Check that expo-module.config.json includes the plugin reference
  4. Confirm @expo/config-plugins is installed

Hash Mismatch

Symptoms: All requests to a specific host fail

Solutions:

  1. Regenerate the SPKI hash using the commands above
  2. Make sure you're hashing the public key, not the certificate
  3. Verify you're using base64 encoding (not hex)
  4. Test with a tool like openssl s_client to ensure the server is using the expected certificate

Certificate Rotation Strategy

  1. Get new certificate from your CA
  2. Generate SPKI hash for the new certificate
  3. Add new hash as backup in your app config
  4. Release app update with both old and new hashes
  5. Wait for users to update (2-4 weeks recommended)
  6. Install new certificate on your server
  7. Remove old hash in next app version (optional)

Examples

Example: Development vs Production

const sslConfig = {
  sslPinning: {
    hosts: {},
  },
};

// Only enable SSL pinning in production builds
if (process.env.APP_ENV === "production") {
  sslConfig.sslPinning.hosts["api.production.com"] = [
    process.env.SSL_HASH_PRIMARY,
    process.env.SSL_HASH_BACKUP,
  ];
}

export default {
  expo: {
    plugins: [["expo-ssl-pinning", sslConfig]],
  },
};

Example: Multiple Environments

const API_CONFIGS = {
  production: {
    host: "api.production.com",
    hashes: ["prodHash1==", "prodHash2=="],
  },
  staging: {
    host: "api.staging.com",
    hashes: ["stagingHash1==", "stagingHash2=="],
  },
};

const currentEnv = process.env.APP_ENV || "staging";
const config = API_CONFIGS[currentEnv];

export default {
  expo: {
    plugins: [
      [
        "expo-ssl-pinning",
        {
          sslPinning: {
            hosts: {
              [config.host]: config.hashes,
            },
          },
        },
      ],
    ],
  },
};

Security Considerations

  • This is not a silver bullet - SSL pinning is one layer of defense
  • Combine with other security measures (e.g., API authentication, encryption)
  • Attackers with physical device access can potentially bypass pinning (jailbreak/root)
  • Certificate transparency - your pins are visible in the app binary
  • Keep certificates secure - protect your private keys

Requirements

  • Expo SDK 48+
  • React Native 0.71+
  • iOS 13.0+
  • Android 6.0+ (API level 23+)

Contributing

Contributions are welcome! Please open an issue or submit a PR.

License

MIT

Author

Eric Mensah (@teincsolutions)

Support

For issues and questions:

  • Open an issue: https://github.com/teincsolutions/expo-ssl-pinning/issues
  • Email: [email protected]

Changelog

0.1.0 (Initial Release)

  • iOS SSL pinning via URLSession
  • Android SSL pinning via OkHttp
  • Config plugin for automatic configuration
  • Support for multiple hosts and backup keys