How to store secrets in a mobile app without hardcoding them
You can't safely ship a real secret in a client app — anything in the binary is extractable. The right patterns: keep secrets server-side, use the platform keystore, and restrict any key that must ship.
Last updated 2026-09-07
Read in context. These instructions need to be adapted to your app and platform version. New scans provide static detections; they do not establish current backend access. Current methodology.
Why a client can't hold a secret
Everything shipped in an APK/IPA travels to the user's device and can be recovered — from resources, the DEX, or native .so files. Obfuscation, string "encryption", and moving the value into the NDK all raise the effort slightly but don't change the outcome: a determined attacker (or an automated scanner) extracts it. So the goal isn't to hide the secret — it's to not ship one.
Pattern 1 — keep it server-side (the default)
Put the API call behind your own backend. The app authenticates the user (OAuth/OIDC with PKCE, or your session), your backend holds the third-party key and makes the call, and returns only what the user is allowed to see. The client never sees the key.
Pattern 2 — platform key stores for on-device data
For secrets that must live on the device (a derived token, encryption keys for local data), use the Android Keystore / iOS Keychain — hardware-backed where available, so the key material isn't extractable even from a rooted device. Never roll your own with a hardcoded key.
Pattern 3 — restrict keys that must ship
Some keys are designed to be public (a Google Maps key, a Firebase config). Make a leaked copy worthless: apply application + API restrictions (package name + signing cert + specific APIs) in the provider console, add Firebase App Check, and set spend/quota limits. The key ships, but only your app can use it.
What doesn't work
- Obfuscation / string encryption — the app must decrypt at runtime, so the value is recoverable. Defense-in-depth at best, never the control.
- Hiding in the NDK — native strings are just as extractable (often easier — a plain
stringspass). - Split/encoded keys — reassembled at runtime, recovered at runtime.
Maps to CWE-798 and MASVS-STORAGE-1. If you already shipped one, find it and rotate immediately.
Frequently asked questions
Can't I just obfuscate or encrypt the key?
No — the app has to decrypt it to use it, so anyone running/decompiling the app recovers it. Obfuscation slows a casual look; it doesn't protect a secret from a scanner or a motivated attacker.
Is putting the key in native (NDK) code safer?
Marginally, and not meaningfully. Native binaries are readable; hardcoded strings/keys in a .so are extractable, often with a simple strings dump. It's not a secret store.
What about API keys that genuinely must be in the app?
Restrict them so a leaked copy is useless: lock to your package + signing cert + specific APIs, add App Check/attestation, and cap quota. The key can be public as long as only your app can successfully use it.