skip to content

A React Native payments app pins its API key and the server certificate is being replaced; how do you rotate without locking out users who never update?

level: seniorimportance: should knowfreq 34%

answer

  1. installed binaries carry old pins
  2. renew with the same key when possible
  3. backup pin shipped a release ahead
  4. pin-set expiration fails open
  5. OTA cannot change native pins

basics

~20 s

Plan rotation around the oldest app still in use: renew with the same key where possible, and when the key must change, switch to a backup key whose pin already shipped. An expiration date on Android pins and a forced-update path limit lock-out.

solid answer

~40 s

Every installed binary carries the pins it was built with, and pins in a network security config or `Info.plist` are **native** configuration, so an over-the-air JavaScript update cannot change them. Rotation therefore works backwards from the oldest version still in use. If the certificate is only being **renewed**, reuse the same key pair and nothing breaks. If the key must **change**, the new key's pin must already be in every supported version: that is what the backup pin is for; serve the backup key, then ship a release that pins the new current key plus a fresh backup. On Android, a `pin-set` `expiration` date makes very old installs stop enforcing pins instead of failing forever. Pair this with a server-driven minimum-version check so hopelessly old builds can be told to update.

go deeper

for a junior

Remember that pins are baked into the installed app, so changing the server key can break old versions.

for a middle

Explain why OTA updates cannot change pins, and what backup pins and Android's pin expiration do.

for a senior

Run the rotation: oldest supported version, same-key renewal, backup-key switch, next-pair release, monitoring by version.

for a principal

Set the version-support window and key-management process that make rotation routine rather than an incident.

## Why pinned apps get locked out A pin is compiled into the app. Once a user installs version 3.2, that binary checks the server's key against the pins in 3.2, and it will do so until the user updates. If the server presents a key none of those pins match, **every request fails**: login, balances, payments. The user sees a broken app, and support cannot fix it remotely. The React Native security guide warns about exactly this: when a pinned certificate expires and is replaced, apps with the old pin stop working. ## What you cannot use to fix it - **Over-the-air updates.** EAS Update and similar tools ship JavaScript and assets. Pins in `Info.plist` (`NSPinnedDomains`) or in Android's network security config are native configuration, part of the binary, so they need a store release. - **The server.** Once the server has switched keys, old clients cannot be convinced by anything the server says, because they refuse the connection before any response. ## A rotation plan that does not break anyone 1. **Know your oldest active version.** Pins must work for every version you still support, not only the latest. 2. **Prefer renewal with the same key.** Pinning the public key rather than the certificate means a routine renewal that keeps the key pair changes nothing for clients. 3. **Keep a backup pin in every release.** It is the hash of a key pair generated in advance and stored offline. When the key must change, the server moves to the backup key, and every supported version already accepts it. 4. **Ship the next pair early.** In the release after the switch, pin the new current key plus a newly generated backup, and let adoption build up before the next rotation. 5. **Retire old pins only after old versions are gone**, and never remove the pin the server is currently using. ## Safety valves | Mechanism | Platform | What it does | Trade-off | |---|---|---|---| | `pin-set` `expiration` | Android network security config | after the date, pins are not enforced for that domain | old installs fall back to ordinary CA validation instead of failing | | Minimum-version check | your backend and app | the API tells builds below a version to update | only works while the app can still connect, so check it before pins go stale | | Pinning an intermediate key | both | survives changes of your leaf key | depends on staying with that issuing CA | On iOS, `NSPinnedDomains` has no expiration date, so a backup pin and a minimum-version policy matter even more there. ## A worked timeline 1. **Release 5.0** pins key A (current) and key B (backup, offline). 2. Key A must be retired. The server switches to **key B**; every build from 5.0 on keeps working. 3. **Release 5.3** pins key B (now current) and a new backup key C. 4. Months later, once versions before 5.3 have dropped below the support threshold, the minimum-version check blocks them, and the team is ready for the next rotation to key C. At no point does the server present a key that a supported build does not already pin. ## Monitoring before and after - Watch connection-failure rates per app version; a spike on one version after a server change is the lock-out signature. - Rehearse the switch on a staging host with a production build before touching the real API. - Record which key each release pins, so nobody has to reverse-engineer the binary during an incident. ## Common failure stories - The certificate was renewed with a **new key** by default, and the team pinned the leaf key without a backup. - A CDN or load balancer in front of the API presented its own certificate after a configuration change. - The team shipped the new pin and switched the server the same day, stranding everyone who had not updated yet.

  • Why does a pin-set `expiration` date fail open rather than closed?
    After the date Android stops enforcing those pins and falls back to ordinary certificate validation. That trades some protection on very old installs for availability: a user who has not updated for years still gets a working, CA-validated connection instead of a permanently broken app.
  • Can a minimum-version check rescue users who are already locked out?
    No. If the pinned build cannot complete a TLS connection, it never receives the "please update" answer. The check only helps while the old pins still match, which is why it must go live well before any key change.

Pins are house keys you mailed to every tenant. You can change the lock only to one that an already-mailed spare key fits; otherwise tenants who never check their mail are locked out.

saying these in an interview costs you the question

  • An EAS Update can ship new pins to installed apps.
  • A certificate renewal always changes the public key.
  • The server can tell locked-out apps to update.
  • Removing all pins in the next release fixes stranded users.
  • Switching keys the day the new pin ships is safe.