Your app is already on HTTPS. The lock icon is there. The backend is on Firebase or Supabase. Everything looks normal.
Then a user opens the app on café Wi-Fi, hotel Wi-Fi, or an airport network that you don't control. Your app starts sending tokens, profile data, API requests, and signed calls over a connection it believes is legitimate. Most of the time, that trust is fine. Sometimes, for high-risk apps, it isn't enough.
That's where people start asking what is certificate pinning, and whether it still makes sense for modern mobile apps. The short answer is simple. Certificate pinning is a way to make your app trust only a specific server identity instead of the entire public certificate ecosystem. The longer answer is more useful, because pinning can protect the right app very well, and break the wrong app just as effectively.
The Invisible Threat on Public Wi-Fi
A common failure mode starts with a perfectly ordinary user journey. Someone installs your app, logs in, and checks messages or account data while connected to public Wi-Fi. They don't see anything unusual. Your app still shows the same screens. Requests still move between the device and your backend.
What the user can't see is the trust decision happening underneath. If an attacker can insert themselves between the app and the server, they may try to present a server identity that looks valid enough for the device to accept. For a team building a mobile app with sensitive API traffic, that's the core problem to think about first. Not the buzzword. The trust boundary.
Certificate pinning addresses that exact moment. MITRE D3FEND defines it as storing a trusted copy of the server's certificate or public key and comparing it during the TLS handshake. If the server identity doesn't match, the app rejects the connection instead of continuing anyway, as described in MITRE's certificate pinning entry.
What this looks like in practice
Think about a mobile app that talks constantly to one backend. Authentication. Feature flags. Content fetches. Payment status. Session refresh. If the app accepts any certificate that chains back to a generally trusted authority, your trust model is broad. If the app accepts only the specific identity you pre-authorised, your trust model is narrow.
That's why pinning matters most when the client and server relationship is tightly controlled.
Practical rule: Use pinning when the app should speak to one known backend, not to a wide and changing set of third-party hosts.
Teams shipping to users who travel or work from unpredictable networks should also think beyond transport security alone. If you're evaluating exposure on hostile or filtered networks, Throughwire for secure internet in China is a useful operational read because it frames how public and intermediary-controlled networks can alter the security assumptions your app depends on.
For broader hardening around the rest of the app, not just TLS, it also helps to review mobile app security best practices. Pinning can stop one class of trust failure. It won't fix leaked keys, weak auth flows, or an exposed backend.
Why Standard HTTPS Is Not Always Enough
HTTPS solves a big problem. It encrypts traffic and verifies server identity through the public certificate authority model. But it also asks your app to trust a large built-in set of certificate authorities that the operating system already accepts.
For many apps, that model is good enough. For apps with stricter trust requirements, it's broad by design. Your app isn't just trusting your own certificate. It's trusting the wider machinery that can vouch for it.

The chain of trust problem
The normal path looks like this:
- Device trust. The phone trusts the operating system.
- OS trust. The operating system trusts a list of certificate authorities.
- CA trust. Those authorities can issue certificates that the device will accept for TLS.
- App trust. Your app inherits that decision unless you narrow it.
That chain is convenient. It's also the reason pinning exists. With pinning, the app stops trusting the whole approved world for that one endpoint and starts trusting only the certificate or key you decided to allow.
For a modern mobile app, this matters more than many teams realise. If you're using Firebase or Supabase, a lot of business value is concentrated in API calls. Auth tokens, row-level data access, edge function traffic, storage access, and service-to-app flows all depend on the app talking to the right backend, every time.
Why this became a mobile-first control
Certificate pinning became prominent in mobile deployments where one organisation controls both the client and server. OWASP notes that this is the right kind of environment for pinning, and also warns that certificate rotation can cause outages if you get the process wrong, as described in OWASP's guidance on certificate and public key pinning.
That history matters because browser-era thinking still confuses teams. Browser-focused HPKP is obsolete. Mobile app pinning is different. It's niche, deliberate, and only sensible when you can manage both ends of the connection.
Standard TLS answers, “Is this certificate broadly trusted?” Pinning answers, “Is this the exact server identity my app was built to trust?”
If your app also handles sensitive local data, encrypted transport is only one layer. End-to-end encryption in mobile systems is a separate design choice with a different threat model. Teams often mix those up. Pinning protects server trust. It doesn't create end-to-end secrecy by itself.
Comparing Pinning Approaches
Once you've decided pinning might fit, the next question is what exactly to pin. The implementation usually stores a certificate, a public key, or a fingerprint/hash and compares the live server chain against that expected value. If the values don't match, the client terminates the connection, as outlined in this certificate pinning implementation overview.
The easiest way to think about the options is identity checking.
- Pinning the full certificate is like checking someone's entire passport, including details that may change on renewal.
- Pinning the public key is like checking the person's face rather than the whole document.
- Pinning a hash fingerprint is like checking a compact, unique representation of that face.
What each method buys you
The more tightly you pin, the less flexibility you keep during certificate renewals or infrastructure changes. That trade-off is the heart of real-world pinning.
| Pinning Method | How It Works | Pros | Cons | |---|---|---|---| | Certificate pinning | The app stores and compares the full certificate | Simple to understand. Strongly tied to one exact certificate | Brittle during renewal. A normal replacement can break the app | | Public key pinning | The app stores the expected public key and accepts certificates carrying that key | More flexible than full certificate pinning. Better fit for renewals that reuse the key | Still needs planning if key material changes | | Fingerprint or hash pinning | The app stores a hash of the certificate or key and compares against the live value | Compact and practical. Common in implementation | Easy to operationally mishandle if teams don't track what the hash represents |
What usually works best
For most mobile teams, public-key pinning is the practical choice. It gives you tighter trust than default TLS without coupling the app to every detail of one leaf certificate. That flexibility matters when certificates renew as part of normal operations.
Full certificate pinning tends to create avoidable pain. It's strict in a way that infrastructure teams dislike and on-call engineers eventually inherit.
A workable pinning setup usually includes:
- A primary and backup pin so you're not trapped by one unexpected change
- A documented rotation process owned by engineering, not left as tribal knowledge
- Monitoring before rollout so the cert or key presented in production is what you expect
- A clear rollback path if the app starts rejecting legitimate traffic
Operational test: If your team can't explain how it will rotate pins without an emergency app release, it isn't ready to ship pinning.
Implementing Pinning in Android and iOS Apps
The safest implementations are the ones that reduce custom code and make review easier. Hard-coding ad hoc checks deep inside networking layers usually ages badly. Declarative configuration and well-contained validation logic are easier to reason about.

Android with Network Security Configuration
On Android, the cleanest modern pattern is usually Network Security Configuration. It keeps trust rules in XML rather than scattering them through OkHttp interceptors or custom socket code.
A simplified example looks like this:
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<domain-config>
<domain includeSubdomains="true">api.example.com</domain>
<pin-set>
<pin digest="SHA-256">BASE64_ENCODED_PRIMARY_PIN</pin>
<pin digest="SHA-256">BASE64_ENCODED_BACKUP_PIN</pin>
</pin-set>
</domain-config>
</network-security-config>
Then reference it in the manifest:
<application
android:networkSecurityConfig="@xml/network_security_config"
... >
</application>
This pattern works well because the trust rule is explicit. Reviewers can inspect the domains, see the pin set, and confirm that there's a backup pin. For an Android app that talks to a fixed API host, that's much safer than bespoke validation hidden in a networking helper.
A few implementation notes matter:
- Scope domains carefully. Don't pin a broad host pattern if only one API host needs strict trust.
- Keep backup material ready. A single pin is a future outage waiting to happen.
- Avoid mixing environments. Development, staging, and production often need different configurations.
iOS with URLSession validation
On iOS, teams typically implement pinning through a URLSession delegate that inspects the server trust challenge and compares the certificate or public key against expected pinned material.
A simplified pattern looks like this:
final class PinnedSessionDelegate: NSObject, URLSessionDelegate {
private let expectedKeyHash = "BASE64_ENCODED_PUBLIC_KEY_HASH"
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// Perform normal trust evaluation first.
// Extract certificate/public key.
// Compute hash and compare to expectedKeyHash.
let isPinnedMatch = true // Replace with real comparison result
if isPinnedMatch {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
The key point isn't the sample code. It's the sequence. Do normal certificate validation first, then apply pinning as an extra trust check. Pinning isn't a replacement for hostname validation and chain validation.
What to do with Firebase and Supabase
Many teams reach a practical limit. If your mobile app calls only your own API gateway in front of Firebase or Supabase, pinning is feasible. If the app directly depends on a wider set of managed service endpoints, CDNs, or third-party SDK traffic, pinning gets harder to maintain.
That's why I usually push teams to map outbound hosts before they implement anything. Know exactly which domains the app must trust. If the answer is messy, pinning will be messy too.
For BaaS-heavy apps, keep these rules in mind:
- Pin only what you control. If the endpoint lifecycle is owned by the platform, your room to pin safely may be limited.
- Prefer configuration over cleverness. A simple, reviewable trust policy beats a custom framework every time.
- Plan updates before release. If you can't update pin sets quickly, don't rely on pinning as your primary transport hardening layer.
How Pinning Is Tested and Bypassed
Pinning helps. It doesn't make your app unbreakable.
Attackers and mobile security testers don't always attack the network. Often they attack the app itself. If they can instrument the client, hook certificate validation, or patch the binary, they may bypass your pinning checks and restore proxy visibility.

The tools defenders should know
In mobile assessments, testers commonly use tools such as Burp Suite or Charles to inspect proxied traffic. If pinning is active, that proxying usually fails first. Then the focus shifts to bypass.
Typical bypass workflows involve:
- Frida for runtime instrumentation and method hooking
- Objection for easier interaction with instrumented mobile apps
- Patched builds that alter trust logic in the application binary
- Rooted or jailbroken environments where app protections are easier to tamper with
A defender doesn't need offensive detail to understand the lesson. If trust decisions happen in a client the attacker controls, some determined attackers will eventually modify that client.
What this means for your threat model
Pinning is strongest against interception on the wire. It's weaker against a hostile device where the app runtime itself is under pressure.
That's why experienced teams treat pinning as one layer in a stack that may also include device integrity checks, jailbreak or root detection, app attestation, careful token handling, and backend-side abuse controls.
Pinning blocks the easy path for traffic interception. It does not remove the need to secure the client, the API, and the authorisation model behind them.
If you want to validate whether your app's trust controls hold up under instrumentation and runtime tampering, that belongs in a proper mobile app penetration testing process, not in a checkbox exercise.
A good internal test asks practical questions:
- Can a proxy see traffic after a basic bypass attempt?
- Does the app fail closed when trust validation breaks?
- Are secrets or tokens still exposed elsewhere even if transport pinning works?
- Can an attacker call the backend directly and avoid the app altogether?
That last point matters a lot for Firebase and Supabase apps. If backend rules are weak, pinning may protect transit while the underlying issue sits in permissive access controls.
The Hidden Costs and Modern Alternatives
The hardest part of certificate pinning isn't the code. It's the operations.
Microsoft describes pinning as accepting only authorised certificates and rejecting anything else during session establishment, and explicitly advises that pinned certificates must be updatable on short notice because rotation, expiry, or CA changes can otherwise break connectivity, as noted in Microsoft's certificate pinning guidance.
Where teams get hurt
The failure mode is blunt. Your infrastructure changes in a legitimate way. Your app still expects the old identity. Users can't connect.
For a startup, that can be worse than the risk pinning was meant to reduce. You may not control update speed. Users may stay on older builds. Emergency releases may take time to propagate. Support gets flooded while engineering tries to work out whether the fault is in mobile, networking, or certificates.
These are the hidden costs teams underestimate:
- Release dependency. Static pins can turn certificate maintenance into an app release problem.
- Environment sprawl. Staging, preview, and production don't always present the same trust material.
- Third-party coupling. Managed endpoints and SDK dependencies can change on schedules you don't control.
Alternatives that are often easier to live with
If your real concern is abuse from unofficial clients, app attestation is often a better fit than pinning. For Firebase teams, App Check is the obvious example. It's not the same control, but it addresses a different and very common problem. It helps your backend distinguish legitimate app instances from scripted or repackaged clients.
You can also reduce risk with less operational fragility by combining:
- Certificate Transparency monitoring to detect unexpected certificate issuance affecting your domains
- Strong backend authorisation so even intercepted requests are limited in what they can do
- Short-lived tokens and server-side checks that reduce replay value
- Host mapping discipline so the app talks to a minimal, well-understood set of endpoints
For many Firebase and Supabase apps, that package is more realistic than strict pinning. It won't satisfy every high-assurance requirement, but it's often the right engineering trade.
Decision lens: If your team moves fast, depends heavily on managed services, and can't guarantee rapid client updates, a manageable control that stays on is better than a stronger control that fails in production.
Practical Guidance for Your App Stack
The right answer depends less on theory and more on your operating model.
If you're building a banking app, a regulated health app, or an internal enterprise app with a fixed backend and strong release control, pinning is still a serious option. Use public-key style pinning, keep backup pins, and rehearse certificate rotation before shipping.
If you're building a startup app on Firebase or Supabase with frequent releases, third-party SDKs, and a user base you can't force-update, be more selective. Pin only the endpoints you own and understand. For many teams, app attestation, strong backend rules, and transport monitoring are the smarter baseline.
A quick decision checklist helps:
- High sensitivity. Would intercepted API traffic create severe user or business harm?
- Tight endpoint control. Do you control both the mobile client and the server identity lifecycle?
- Fast update path. Can you update trust material quickly if certificates change?
- Low downtime tolerance. Can the business absorb a trust misconfiguration outage?
- BaaS complexity. Does the app depend on platform-managed hosts that make pinning awkward?

If most of those answers support control and predictability, pinning can add real value. If they point to operational fragility, don't force it. Standard TLS plus better app and backend controls is often the more professional choice.
If you're building on Supabase, Firebase, or shipping a mobile app with backend integrations, AuditYour.App helps you check the rest of the attack surface that pinning won't cover, including exposed rules, unprotected RPCs, leaked secrets, and mobile bundle issues. It's a practical way to find the mistakes that usually matter first.
Scan your app for this vulnerability
AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.
Run Free Scan