Skip to main content
Security7 min readNovember 3, 2025

Mobile App Security: Protecting User Data on Device

Practical mobile app security practices — secure storage, certificate pinning, biometric auth, API security, and the threats that actually matter in production.

James Ross Jr.
James Ross Jr.

Strategic Systems Architect & Enterprise Software Developer

Mobile apps operate in a fundamentally different security environment than web applications. The device is in the user's hands, which means your app runs on hardware you do not control, alongside other apps you did not install, on networks you cannot trust. Every security decision needs to account for that reality.

I have reviewed the security architecture of dozens of mobile apps. The mistakes are remarkably consistent, and most are preventable with straightforward practices.

Secure Data Storage

The most common security mistake in mobile apps is storing sensitive data in plaintext. It sounds obvious, but I regularly see authentication tokens in AsyncStorage, API keys hardcoded in the bundle, and user data written to unencrypted files.

On iOS, use the Keychain for sensitive values like tokens, passwords, and encryption keys. The Keychain is encrypted at the hardware level and protected by the device passcode. For less sensitive but still private data, use encrypted Core Data stores or the file protection API with the appropriate protection class.

On Android, use the Android Keystore system for cryptographic keys and EncryptedSharedPreferences for sensitive key-value data. The Keystore ties encryption to the device's hardware security module when available, making extracted data useless on other devices.

For cross-platform apps, libraries like react-native-keychain and flutter_secure_storage abstract these platform APIs. Use them. The default storage mechanisms — AsyncStorage, SharedPreferences — are not encrypted and should never hold sensitive data.

Beyond storage, think about data in memory. Sensitive values should be cleared from memory when no longer needed. On Android particularly, the garbage collector does not guarantee when memory is released, so explicitly zeroing sensitive buffers matters.

Network Security

Every API call from your mobile app should go over HTTPS. That is table stakes. But HTTPS alone is not enough because users can install custom root certificates, and attackers on shared networks can intercept traffic with proxy tools.

Certificate pinning adds a layer by verifying that the server's certificate matches a known value, not just that it is signed by a trusted authority. This prevents man-in-the-middle attacks even when a malicious root certificate is installed. Implement pinning for your authentication and payment endpoints at minimum.

However, certificate pinning creates operational complexity. When your server certificate rotates, pinned apps stop working. Plan for this by pinning the public key rather than the full certificate, including backup pins, and having a mechanism to update pins without an app store release. This is one area where the API security practices for mobile differ meaningfully from web.

Beyond pinning, implement request signing for sensitive operations. Attach an HMAC to critical API requests using a device-specific key. This prevents replay attacks and ensures request integrity even if someone manages to observe the traffic.

Authentication and Biometrics

Mobile authentication should take advantage of what the device offers. Biometric authentication — Face ID, Touch ID, fingerprint sensors — provides both security and convenience. Users are more likely to use strong authentication when it does not require typing a password every time.

Implement biometrics as a local unlock mechanism, not as the sole authentication factor. The flow should be: user authenticates with credentials on first login, receives a token, stores the token in the secure keychain protected by biometric access control. On subsequent launches, biometric verification unlocks the stored token. If biometric fails, fall back to credentials.

Session management on mobile differs from web. Mobile apps stay installed and users expect to stay logged in across sessions. Use refresh tokens with reasonable expiration — long-lived enough to avoid constant re-authentication, short-lived enough that a stolen token has limited value. Rotate refresh tokens on each use and invalidate the old one.

For apps handling financial or health data, implement step-up authentication. Normal browsing uses the cached session, but sensitive operations like transfers or data exports require fresh biometric or PIN verification. This mirrors what users expect from banking apps.

Protecting the App Itself

The compiled app bundle ships to the user's device, where it can be reverse engineered, modified, and redistributed. Complete protection is impossible — any code running on a device you do not control can eventually be analyzed. But you can raise the bar significantly.

Code obfuscation makes reverse engineering harder. For React Native, tools like Hermes pre-compilation make the JavaScript harder to read than plain bundle files. For native code, enable compiler optimizations and consider commercial obfuscation tools for high-value applications.

Runtime integrity checks detect whether the app has been tampered with. Check the app signature at launch, detect debugger attachment, and verify that the runtime environment is not rooted or jailbroken (while handling these cases gracefully — some legitimate users have rooted devices).

Do not rely on client-side validation for anything security-critical. Every check that matters must also happen on the server. The client can always be modified. Client-side checks provide defense in depth, not primary security.

When building your mobile app architecture, treat security as a foundational concern, not a feature to add later. Retrofitting secure storage, certificate pinning, and proper authentication into an existing app is significantly more work than building them in from the start. The security architecture should be in your first sprint, not your last.