Mobile App Security Architecture
Last quarter, a fintech client in Gurgaon shipped a UPI-linked wallet to production with refresh tokens stored in AsyncStorage and API keys embedded in the React Native bundle. Penetration testing took four days. The testers extracted the staging API key from a decompiled APK, replayed refresh tokens from a rooted emulator, and initiated fund transfers that bypassed device binding. None of this required exotic tooling—just MobSF, Frida, and patience.
The product team had followed a checklist: HTTPS everywhere, bcrypt on the server, two-factor authentication for high-value transfers. What they lacked was a coherent mobile app security architecture—a set of layered decisions about where secrets live, how the client proves its identity, and what the backend trusts when a request arrives from a phone on a patchy 4G connection in Noida.
We rebuilt the architecture over six weeks without rewriting the entire app. The lesson was not that mobile security is impossible on a startup budget. It is that security controls must be designed as a system, not sprinkled on after feature development. This article documents the architecture we recommend when CTOs and founders ask us how to secure a mobile app without turning every login into a fifteen-step ordeal.
What You Will Learn
- Map a threat model across client, transport, API, and backend layers—and decide what you will not try to defend on-device
- Implement token storage, certificate pinning, and session handling using platform-native primitives (Android Keystore, iOS Keychain, OAuth 2.0 + PKCE)
- Align your release pipeline with OWASP mobile security 2026 expectations: MASVS Level 1 for most apps, Level 2 when handling payments or health data
- Choose between attestation (Play Integrity, App Attest), root detection, and server-side risk scoring—with honest trade-offs on each
- Structure backend API gates so compromised clients cannot escalate privilege through replay or token theft
- Estimate security engineering cost in INR and sequence work across MVP, growth, and compliance phases
- Apply mobile app security best practices that survive Indian network conditions, device fragmentation, and DPDP Act obligations
The Client Layer: Assume the Device Is Hostile
Every serious mobile app security architecture starts with one assumption: the client runs on hardware you do not control. Users install sideloaded builds. They run Magisk on Android or jailbreak iOS. They share phones with family members. They dismiss security prompts because the OTP arrived late on Jio during peak hours.
That means secrets that unlock money, health records, or admin access must never live in plaintext on the device. It also means client-side validation is UX convenience, not security. Your architecture should treat the mobile app as an untrusted presentation layer that holds short-lived credentials and renders responses from a server that makes the real authorization decisions.
What belongs on-device versus on-server
We keep on-device: access tokens with TTL under fifteen minutes, non-sensitive UI preferences, cached public content, and device-specific keys generated inside secure hardware when available. We never keep on-device: long-lived refresh tokens without hardware binding, payment signing keys, admin credentials, or PII that regulations classify as sensitive personal data under India's Digital Personal Data Protection Act.
For a healthcare app development engagement, we extend this boundary further: clinical identifiers and diagnostic summaries stay encrypted at rest with keys the server rotates, and the app fetches them only after step-up authentication. Storing a patient's full record locally because "offline mode is a nice feature" creates an audit trail problem you cannot fix with a patch release.
Secure storage: platform primitives, not DIY encryption
Teams often roll custom AES wrappers around SharedPreferences or UserDefaults. We discourage this unless you have a cryptographer reviewing the implementation quarterly. Android's EncryptedSharedPreferences (backed by Android Keystore) and iOS Keychain with kSecAttrAccessibleWhenUnlockedThisDeviceOnly give you hardware-backed protection on most devices shipping in India today.
The limitation is real: on devices without TEE support or with known Keystore bugs on older OEM skins, encrypted storage degrades to software-only protection. Your architecture must account for that by keeping token lifetimes short and pairing storage hardening with server-side session revocation.
Why we store refresh tokens in the Keystore, not AsyncStorage
This is the single highest-impact client change we make on React Native and Flutter audits. AsyncStorage, MMKV without encryption, and plain SQLite are fine for theme preferences. They are not fine for OAuth refresh tokens.
// Android: refresh token in EncryptedSharedPreferences + Keystore
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val securePrefs = EncryptedSharedPreferences.create(
context,
"auth_vault",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
fun saveRefreshToken(token: String) {
securePrefs.edit()
.putString("refresh_token", token)
.apply()
}
fun clearOnLogout() {
securePrefs.edit().clear().apply()
// Also revoke server-side — client clear alone is insufficient
}
iOS Keychain with device-only accessibility
On iOS, we mirror the same policy with Keychain items that do not sync via iCloud and require the device passcode gate. Swift's Security framework is verbose; we wrap it once and reuse across projects.
enum KeychainError: Error { case unexpectedStatus(OSStatus) }
func saveRefreshToken(_ token: String, service: String) throws {
let data = Data(token.utf8)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: "refresh_token",
kSecAttrAccessible as String:
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
kSecValueData as String: data
]
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else {
throw KeychainError.unexpectedStatus(status)
}
}
Transport and Session Architecture
TLS 1.2+ with strong cipher suites is table stakes. It is also insufficient when users install corporate MITM proxies, when outdated devices trust compromised CAs, or when an attacker on the same café Wi-Fi in Connaught Place runs sslstrip against apps that do not pin certificates.
Certificate pinning: when we require it
We require pinning for fintech, healthcare, and any app handling government-issued identifiers. We often skip pinning for content-heavy consumer apps where CDN certificate rotation would break older builds in the field—unless the app handles authenticated sessions on the same domain.
Pinning trades operational flexibility for tamper resistance. If you pin to a leaf certificate that expires in ninety days and forget to ship an app update, you lock out users. We pin to SPKI hashes of intermediate CAs and maintain a backup pin for rotation. We also implement a controlled break-glass path: a remote config flag that disables pinning only after two failed app versions have been pulled from stores—never a silent server-side disable on every request.
// React Native 0.76+ with react-native-ssl-pinning
import { fetch } from 'react-native-ssl-pinning';
const PINNED_HOST = 'api.example.com';
export async function secureGet(path: string, accessToken: string) {
const response = await fetch(`https://${PINNED_HOST}${path}`, {
method: 'GET',
timeoutInterval: 15000,
sslPinning: {
certs: ['api_example_com'], // .cer in android/app/src/main/res/raw/
},
headers: {
Authorization: `Bearer ${accessToken}`,
'X-Request-Id': crypto.randomUUID(),
},
});
if (response.status === 401) throw new Error('SESSION_EXPIRED');
return response.json();
}
OAuth 2.0 + PKCE and refresh token rotation
Password grants are dead. Authorization Code with PKCE is the baseline for native apps in 2026. Our session architecture looks like this: short-lived access tokens (5–15 minutes), rotating refresh tokens bound to a device ID, and server-side session tables that store token family hashes—not the raw tokens themselves.
When a refresh token is reused after rotation, we treat it as a theft signal: revoke the entire token family, force re-authentication, and log the event for fraud review. This pattern costs more backend engineering than stateless JWTs, but it closes the replay window that bit our Gurgaon fintech client.
API and Backend Gates: Where Real Authorization Lives
The mobile app requests. The API decides. Every sensitive operation—transfer initiation, prescription upload, admin configuration—passes through gates that do not trust client claims about user role or account balance.
Defense in depth on the server
Our standard backend stack for Indian deployments runs behind AWS ALB or Cloudflare, with WAF rules tuned for mobile traffic patterns: rate limits per device fingerprint and IP, geo-fencing for admin endpoints, and payload size caps on upload routes. Application-layer checks include scoped OAuth tokens (a read-only token cannot call POST /transfers), idempotency keys on financial writes, and server-computed risk scores that may trigger step-up authentication regardless of what the app UI shows.
For teams already on Firebase, we document the hidden risks in our guide on Firebase cost and security issues—Firestore security rules are not a substitute for an API gateway when money moves.
Device attestation and integrity checks
Root detection and jailbreak flags are noisy. Legitimate power users trigger them; sophisticated attackers hide them. We use Google Play Integrity API (Android) and Apple App Attest (iOS) as signals, not verdicts. A failed integrity check might block high-value transfers while still allowing balance enquiries.
Attestation adds latency—200–800 ms on Indian networks—and fails on sideloaded enterprise builds. Budget for a fallback path: step-up OTP via bank-grade SMS gateway, not a hard crash loop.
CI pipeline gates aligned with OWASP MASVS
We wire security checks into CI so they run on every release candidate, not once before launch. OWASP Mobile Application Security Verification Standard (MASVS) Level 1 covers baseline storage, network, and platform interaction controls. Level 2 adds reverse-engineering resistance and advanced auth—appropriate for wallets and clinical apps.
# .github/workflows/mobile-security.yml (excerpt)
name: mobile-security-gates
on:
pull_request:
paths: ['android/**', 'ios/**', 'src/**']
jobs:
dependency-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: OWASP Dependency-Check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'mobile-client'
path: '.'
format: 'HTML'
args: >
--enableExperimental
--failOnCVSS 7
mobsf-scan:
runs-on: ubuntu-latest
needs: dependency-check
steps:
- uses: actions/checkout@v4
- name: Build debug APK
run: ./gradlew assembleDebug
- name: MobSF static scan
run: |
docker run --rm -v "$PWD:/src" opensecurity/mobile-security-framework-mobsf \
python3 scan.py /src/android/app/build/outputs/apk/debug/app-debug.apk
Reverse Engineering Resistance: Honest Expectations
Obfuscation (ProGuard/R8 on Android, Swift symbol stripping on iOS) raises the cost of static analysis. It does not stop a determined attacker. We use R8 full mode with custom dictionaries on Android release builds, strip debug symbols on iOS, and move business logic that must stay secret to the server.
Frida hooking defeats most client-side checks within hours. That is why we do not store HMAC signing secrets in the binary—even obfuscated. If your payment gateway requires a client-side signature, use a server-mediated signing endpoint with per-transaction nonces.
Runtime Application Self-Protection (RASP) SDKs from vendors like Guardsquare or Promon add tamper detection and debugger blocking. They cost ₹3–8 lakh annually for mid-size apps and complicate debugging. We recommend them when threat models include organised fraud rings targeting a specific APK—not for every MVP.
Reference Architecture
The diagram below shows the layered model we implement on most production apps. Arrows indicate trust boundaries, not data flow alone. Every boundary crossing is an opportunity to validate, rate-limit, or reject.
┌─────────────────────────────────────────────────────────────────────────┐
│ MOBILE CLIENT (UNTRUSTED) │
├─────────────────────────────────────────────────────────────────────────┤
│ UI Layer │ Auth Module (PKCE) │ Secure Storage │
│ (no secrets) │ Biometric gate │ Keystore / Keychain │
├────────────────────┴────────────────────────┴───────────────────────────┤
│ Transport: TLS 1.3 + Certificate Pinning (SPKI) + Request signing │
│ Integrity: Play Integrity / App Attest (risk signal, not sole gate) │
└───────────────────────────────────┬─────────────────────────────────────┘
│ HTTPS (pinned)
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ EDGE / API GATEWAY │
├─────────────────────────────────────────────────────────────────────────┤
│ WAF + Rate Limiting │ mTLS (B2B) │ JWT validation │ Geo rules │
└───────────────────────────────────┬─────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ APPLICATION SERVICES │
├─────────────────────────────────────────────────────────────────────────┤
│ OAuth Server │ Business Logic │ Risk Engine │
│ (rotating refresh) │ (authz checks) │ (step-up triggers) │
├──────────────────────┴─────────────────────┴────────────────────────────┤
│ Audit Log (immutable) │ Idempotency Store │ Session Revocation │
└───────────────────────────────────┬─────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ DATA LAYER: Encrypted at rest (AES-256) │ Secrets Manager │ HSM/KMS │
└─────────────────────────────────────────────────────────────────────────┘
Figure 1: Mobile app security architecture with explicit trust boundaries between client, edge, application, and data layers.
Token Storage and Attestation: Comparison
| Approach | Security posture | Operational cost | Failure modes |
|---|---|---|---|
| AsyncStorage / plain prefs | Low — trivial extraction via backup or root | Minimal dev effort | Token theft, account takeover at scale |
| EncryptedSharedPreferences / Keychain | Medium-high — hardware-backed on modern devices | Low — platform APIs, ~2–3 dev days | Older OEM Keystore bugs; no protection if device unlocked |
| Biometric-gated Keychain access | High for local access control | Medium — UX friction on every cold start | Family device sharing; fallback PIN path must be secure |
| Play Integrity + server-bound refresh | High for fraud reduction | High — backend session infra, attestation latency | Enterprise sideloads; degraded networks in tier-2 cities |
| Best for | Consumer content apps: encrypted storage + short TTL. Fintech/health: attestation signals + rotating refresh + step-up auth on sensitive actions. | ||
| Pinakinvox recommendation | Ship encrypted Keystore/Keychain storage and PKCE from MVP. Add pinning and attestation before handling real money or PHI. Never defer refresh token rotation—it is cheaper to build early than to retrofit under incident pressure. | ||
Choosing the Right Approach
Security architecture is not one-size-fits-all. Sequence controls based on data sensitivity, regulatory exposure, and release velocity.
If you are pre-revenue MVP with no payment or health data, implement MASVS Level 1 basics: HTTPS, encrypted token storage, no secrets in the bundle, dependency scanning in CI, and server-side authorization on every mutating endpoint. Skip RASP and attestation until you have users worth attacking. Our MVP development engagements include a security baseline checklist so you do not rebuild auth in month nine.
If you process UPI, card, or wallet transactions, add certificate pinning, refresh token rotation, Play Integrity/App Attest signals, and a server-side risk engine with step-up OTP for anomalous transfers. Align with RBI's digital payment security controls and PCI-DSS mobile guidance if card data touches your infrastructure—even briefly.
If you handle clinical or insurance data, treat the app as a thin client. Minimise local PHI retention, encrypt at rest with rotating keys, log access for audit, and design offline sync with conflict resolution that never stores unencrypted records. Partner with a team experienced in healthcare application development that understands CDSCO and clinical data handling—not just HIPAA checklists copied from US templates.
If your codebase was generated or heavily assisted by AI tools, run a dedicated security audit before production. AI-generated React Native apps routinely ship with hardcoded API keys, permissive CORS, and Firestore rules that allow public reads. Our AI app security audit service targets exactly these failure patterns.
If you are scaling across Delhi NCR with a distributed team, centralise security decisions in architecture review—not in each sprint's ad hoc fixes. A Gurgaon-based app development partner that shares your timezone can run weekly threat modelling sessions without the async lag that lets insecure shortcuts merge on Friday evenings.
Real-World Example: B2B Field Operations App
We recently hardened a B2B logistics app used by warehouse staff across North India—roughly 12,000 monthly active users on a mix of Samsung A-series and older Xiaomi devices. The original architecture cached JWTs with thirty-day expiry in SQLite and synced order data over unpinned HTTPS because "the CDN certificate changes too often."
After restructuring, access tokens expired in ten minutes, refresh tokens rotated on every use and lived in EncryptedSharedPreferences, and the API rejected requests from clients failing Play Integrity on routes that modified inventory valuations. Offline sync still worked: cached orders used SQLCipher with keys derived from the user's session, wiped on logout. Penetration test findings dropped from eleven critical/high to two medium (both social engineering, not architecture). Crash rates increased by 0.3% due to pinning misconfiguration on one OEM—we fixed it with a remote config pin fallback. Total engineering effort: approximately eight person-weeks, billed in the ₹6–9 lakh range including external pentest.
Frequently Asked Questions
What is the difference between mobile app security architecture and a security checklist?
How does OWASP mobile security guidance apply in 2026?
Is certificate pinning worth the operational risk?
Can root detection or jailbreak blocking make my app secure?
How much does implementing proper mobile app security architecture cost in India?
Do Delhi NCR companies face different mobile security requirements than global startups?
Should we use JWTs or opaque server-side sessions for mobile?
How do we secure AI-generated or low-code mobile apps?
Final Recommendation
We do not recommend chasing perfect on-device security—it does not exist. We recommend a mobile app security architecture that limits blast radius: short-lived tokens in hardware-backed storage, pinned transport for sensitive apps, server-side authorization on every mutation, rotating refresh with theft detection, and CI gates aligned with OWASP MASVS. Add attestation and RASP when your threat model includes targeted fraud, not when you are still validating product-market fit.
The Gurgaon fintech team we opened with could have avoided a rushed six-week retrofit by spending two weeks on architecture during MVP. That is the sequencing we advocate: security primitives first, features second, obfuscation and RASP last. Indian users on mixed networks and mixed devices will not tolerate friction that does not protect them—but they will tolerate a brief biometric prompt before a ₹50,000 transfer if the app has earned trust through consistent, explainable security behaviour.
If you are planning a new build or auditing an existing app before a compliance review, start with a threat model workshop and a MASVS gap assessment. Talk to our mobile development team or reach out directly—we will tell you what to fix now, what to schedule for the next release, and what is not worth your budget.
Need a technical partner?
We design and build production systems. If you are working through the architecture decisions covered here, our engineering team can help you scope, validate, and execute.
Production-verified.
Every architectural pattern published here has been deployed in real client systems — not demo environments.
Written by engineers.
Our architecture articles are written by the engineers who built the systems — not by marketing teams.