Secure Mobile Storage: Keychain vs Keystore and Common Mistakes

Last updated: ⏱ Reading time: ~18 minutes

AI-assisted guide Curated by Norbert Sowinski

Share this guide:

Diagram-style illustration of secure mobile application storage comparing iOS Keychain and Android Keystore, showing access tokens, refresh tokens, cryptographic keys, encrypted local databases, hardware-backed key protection, biometric authorization, backups, logout, rotation, and secure deletion

Mobile apps routinely handle values that should not be stored like normal preferences.

Examples include:

refresh token
private key
database encryption key
session credential
client certificate
user password

A common mistake is to put all of them into:

preferences
JSON file
SQLite row
application constant

simply because those mechanisms are convenient.

Secure mobile storage requires a different question:

What is this value?

What can it authorize?

How long must it exist?

Must it survive backup?

Must it survive device migration?

Should it require user presence?

What happens when it is stolen?

Keychain and Keystore are related ideas, not identical APIs

Apple's Keychain can directly hold small sensitive items such as passwords, tokens, certificates, and cryptographic keys. Android Keystore is primarily a facility for protecting cryptographic keys and restricting how those keys can be used. A common Android design stores the encryption key in Keystore and keeps the resulting ciphertext in normal app-private storage.

1. Start with the secret and threat model

Not every piece of application data requires the same protection.

Public or low-sensitivity state

theme = dark
sort_order = newest
onboarding_complete = true

These usually do not need a secure credential store.

Private user data

cached messages
health records
documents
location history

These may require encrypted database or file storage, but are often too large for a secret store such as Keychain.

Credentials

access token
refresh token
session secret
client certificate

These can authorize actions and deserve stronger protection.

Cryptographic keys

AES database key
private signing key
private authentication key

These are especially useful candidates for platform key-management facilities.

Server secrets do not belong in the app at all

If a secret must remain unknown to the person who owns the phone:

do not ship it
inside the application

Examples include:

Obfuscation can slow inspection, but it does not transform a distributed application secret into a server-side secret.

2. Separate ordinary app data from secrets

Secure mobile storage architecture (diagram)

Secure mobile storage architecture showing user interface and application logic separated from ordinary preferences, application database, secure credential storage, hardware-backed cryptographic keys, encrypted data, authentication server, biometric authorization, backups, and lifecycle operations such as rotation and logout

A useful design has several storage layers.

Ordinary preferences

Store values such as:

UI settings
feature hints
non-sensitive flags

Application database

Store structured data such as:

messages
notes
offline records
cached server data

Secure credential storage

Store or protect:

refresh tokens
password-like credentials
small secret blobs
cryptographic key references

Hardware-protected key layer

Where available and appropriate, cryptographic operations can use keys protected by platform security hardware.

Server-side state

Mobile storage should complement:

The phone should never become the only security boundary.

3. Understand what iOS Keychain provides

Apple's Keychain Services provides storage intended for small pieces of sensitive information.

Typical items include:

Keychain items have accessibility policies

You should choose when an item needs to be available.

For example:

only while device unlocked

or

after first unlock
for background operation

Use the most restrictive policy that still works

If a refresh token is only required while the user is actively using the application:

access while unlocked

may be appropriate.

A background networking feature may require a different accessibility choice.

Device-only policies affect migration

Some Keychain accessibility classes include:

ThisDeviceOnly

semantics.

These items are intentionally not migrated to another device through a backup restore.

Use device binding when that matches the credential

Good candidate:

credential representing
this physical device

Less obvious candidate:

user data that must recover
on a replacement phone

Secure Enclave is not simply “more Keychain”

Secure Enclave-backed cryptographic keys are useful when private-key operations should remain tied to protected hardware.

The application can request cryptographic operations without treating the private key like an ordinary exportable byte string.

User-presence controls can be added

Sensitive operations may be protected with:

device authentication
Touch ID
Face ID

depending on the access-control policy.

Policies tied to the current biometric enrollment should also have an explicit recovery path because enrollment changes can invalidate access.

4. Understand what Android Keystore provides

Android Keystore is commonly misunderstood as:

a secret preferences database

That is not its primary model.

It manages cryptographic key entries and associated key-use restrictions.

Typical Android pattern

Android Keystore
      ↓
AES key
      ↓
encrypt refresh token
      ↓
store ciphertext
in app-private storage

The raw key can remain non-exportable

Instead of:

read raw encryption key
into application code

the application asks the cryptographic provider to perform an authorized operation using the stored key.

Hardware-backed protection varies by device

Depending on hardware and configuration, key material can be protected by an isolated trusted environment or StrongBox-class security hardware.

Do not assume every device has StrongBox

If your application requests a specific hardware capability:

check availability
      ↓
define fallback
or
reject unsupported device

according to the product's risk model.

Keys can have usage restrictions

Android key policies can constrain:

Authentication-bound keys can become invalid

Depending on how the key is configured, changes to secure lock-screen or biometric enrollment state can invalidate the key.

Your application must therefore handle:

key no longer usable

as a real lifecycle state.

Modern Android guidance deserves attention

Older tutorials often center their design around convenience wrappers such as:

EncryptedSharedPreferences
MasterKey

Current Android documentation marks the AndroidX Security Crypto versions of those APIs as deprecated.

For new security-sensitive designs, verify current platform guidance instead of copying an old tutorial unchanged.

5. Store access and refresh tokens deliberately

Mobile secret-storage decision tree (diagram)

Mobile secure-storage decision tree asking whether data is secret, whether it is a cryptographic key, whether it is a small credential or larger dataset, whether it needs biometric authorization, device binding, backup migration or background access, leading to iOS Keychain, Android Keystore, encrypted application storage or ordinary app-private storage

Access token

Usually:

shorter lifetime
used frequently
limited scope

Where practical, an access token can remain only in memory during an active application session.

If the product requires persistence, use storage appropriate to its threat model.

Refresh token

Usually:

longer lived
used less frequently
capable of obtaining
new access tokens

This makes it a higher-value credential.

A common architecture is:

securely stored refresh token
      ↓
authentication server
      ↓
short-lived access token
      ↓
API request

Avoid storing the user's password

Once an authentication protocol has exchanged credentials for suitable session tokens, the application usually should not retain the original account password merely for convenience.

Use server-side rotation where supported

Refresh-token lifecycle may look like:

refresh token R1
      ↓
used once
      ↓
server returns
R2
      ↓
store R2
      ↓
retire R1

Make rotation transactional

Consider:

server invalidates R1
      ↓
server sends R2
      ↓
app crashes before storing R2

Authentication protocols and backend policies should consider interrupted rotation and replay explicitly.

6. Use biometrics to authorize access, not as encryption

Face ID, Touch ID, or Android biometrics are often described as:

encrypting the token

That description is usually too simplistic.

A better model is:

secret / key exists
      ↓
platform access policy
requires authentication
      ↓
user authenticates
      ↓
operation becomes authorized

Decide whether authentication is required every time

Possible policies include:

every sensitive operation

or

for a limited authenticated window

The correct choice depends on:

Do not biometric-lock background credentials accidentally

If a credential is required by:

background refresh
silent push handling
scheduled upload

but its key requires interactive biometric approval every time, background operation may become impossible.

Separate app unlock from server authentication

A local biometric screen can protect access to the app interface.

It does not replace:

backend access-token validation
authorization
revocation
session policy

7. Encrypt larger local datasets with key separation

Secure credential stores are not intended to become multi-gigabyte application databases.

Use envelope-style separation

platform-protected key
      ↓
encrypts / unwraps
data-encryption key
      ↓
encrypts
database or files

Or, for a simpler design:

Keystore-managed AES key
      ↓
encrypt small sensitive values
stored as ciphertext

Protect both confidentiality and integrity

Encryption design should detect unauthorized modification rather than only hide plaintext.

Use established authenticated encryption

Avoid inventing:

custom XOR
custom cipher
home-made key derivation
fixed IV scheme

Never store the encryption key beside the ciphertext

Bad:

database.enc
database-key.txt

in the same ordinary storage location.

Keys and data have separate lifecycles

Deleting a key may make encrypted data permanently unreadable.

That can be useful for:

cryptographic erasure

but only when the product intentionally accepts that recovery model.

Plan for key rotation

Large encrypted datasets may require:

old key
      ↓
decrypt
      ↓
new key
      ↓
reencrypt

or a wrapped data-key architecture that avoids rewriting every file for every wrapping-key change.

8. Design backup and device migration behavior

Backup is part of secure storage.

Ask:

Should this credential
appear on a new phone
after restore?

Some iOS Keychain policies migrate

Other policies with:

ThisDeviceOnly

intentionally do not migrate.

Device-bound authentication should often re-enroll

If the secret represents:

this specific trusted device

restoring it onto another device may defeat that identity model.

Android app files can participate in backup

Ordinary internal application files and preferences can be included in platform backup depending on application configuration.

Do not assume:

app-private
=
never backed up

Encrypted file without its key is not a successful restore

Example:

backup contains ciphertext

new phone does not have
device-bound encryption key

result:
data cannot decrypt

That may be intentional, but the application should recognize and recover from the condition.

Choose one of three recovery models

1. migrate securely

2. restore encrypted data
   and recover key separately

3. intentionally do not migrate
   and require re-authentication

9. Handle logout, account switching, and revocation

Mobile token and key lifecycle (diagram)

Mobile credential lifecycle showing login, token issuance, secure refresh-token storage, short-lived access-token use, token refresh, credential rotation, biometric authorization, account switching, server revocation, logout, local secret deletion, key invalidation, reauthentication and recovery

Logout should have explicit semantics

Possible sequence:

user taps Logout
      ↓
revoke server session
where supported
      ↓
remove refresh token
      ↓
remove access token
      ↓
clear account-specific keys
      ↓
clear protected local data
according to policy
      ↓
return to signed-out state

Local deletion alone may not revoke the session

If a refresh token was copied before logout:

deleting local copy

does not necessarily invalidate the stolen copy.

Server-side revocation remains important.

Account switching requires namespacing

Do not use:

key = "refresh_token"

without understanding which account owns it.

Prefer a model such as:

account ID
+
credential type
+
environment

Never let account B inherit account A's local state

Review:

Handle invalid keys gracefully

If a key becomes unusable because the security configuration changed:

detect
      ↓
clear unusable encrypted session state
      ↓
re-authenticate
      ↓
create replacement key
      ↓
continue

rather than entering an endless crash loop.

10. Avoid common secure-storage mistakes

Mistake 1: storing tokens in plaintext preferences

Convenient storage is not automatically credential-grade storage.

Mistake 2: putting a secret key in source code

const API_SECRET =
"super-secret-production-key"

Anything shipped to the device should be assumed recoverable by a sufficiently motivated analyst.

Mistake 3: Base64 is not encryption

secret
      ↓
Base64
      ↓
still the same secret

Mistake 4: encrypting data and hard-coding the key

encrypted token
+
hard-coded AES key

provides weak separation because the attacker receives both pieces.

Mistake 5: storing the key next to the ciphertext

preferences:
encrypted_token

preferences:
encryption_key

defeats the purpose of platform-protected key storage.

Mistake 6: logging secrets

Never casually log:

Authorization header
refresh token
password
session cookie
private key
database encryption key

Mistake 7: sending secrets to analytics

Analytics attributes and crash-report metadata can persist outside the application's primary security boundary.

Mistake 8: assuming app-private storage means hardware protection

Application sandboxing and hardware-backed key protection solve different problems.

Mistake 9: biometric prompt without cryptographic binding

Showing:

Face ID successful

and then reading an independently accessible plaintext token provides a weaker security model than actually binding sensitive key use or item access to the authentication policy.

Mistake 10: protecting everything with biometrics

Requiring user interaction for every token access may break:

background synchronization
push handling
scheduled operations

Protect according to the actual use case.

Mistake 11: ignoring backups

A perfectly encrypted file can become:

unrecoverable garbage

if the backup restores the ciphertext but not its device-bound key.

Mistake 12: assuming secure storage replaces server security

Even strong local protection does not eliminate:

11. Assume the client can eventually be inspected

Secure mobile storage increases the difficulty of extracting credentials.

It does not make an untrusted endpoint mathematically impossible to inspect.

Threats include

Minimize credential value

Prefer:

short-lived
limited-scope
revocable credential

over:

permanent
global
non-revocable secret

Server authorization is mandatory

Never assume:

request came from our app

therefore

request is authorized

The backend should validate identity and authorization for each protected operation.

Consider device-bound credentials for stronger scenarios

A device can generate a private key locally and register the corresponding public key with the backend.

device
generates private key
      ↓
private key remains protected
      ↓
public key registered
with server

The server can then require proof involving that device-held private key for appropriate workflows.

12. Test the complete secret lifecycle

Fresh installation

Verify:

no old account accidentally loaded
no stale token used
secure storage initializes correctly

Successful login

Verify:

token stored
correct account binding
no secret in logs

Token refresh

Test:

App restart

Verify expected credentials remain available according to policy.

Device lock

Test whether items are accessible at the times your architecture expects.

Biometric changes

For authentication-bound keys, test the platform behavior when:

new biometric enrolled
screen lock removed
authentication policy changes

Backup and restore

Test an actual restore path rather than only reading API documentation.

Verify:

which data migrated
which secrets did not
whether encrypted data still decrypts
whether login is required again

Logout

Verify:

refresh token removed
server session revoked where expected
account cache cleared
in-memory state cleared

Account switching

Confirm user B cannot access:

user A's token
user A's database
user A's cached files

Key invalidation

Simulate a key that can no longer decrypt its data.

The application should recover intentionally rather than repeatedly crash.

13. Copy/paste secure-storage checklist

Secure mobile storage checklist

Threat model
- Inventory sensitive values.
- Identify passwords.
- Identify access tokens.
- Identify refresh tokens.
- Identify private keys.
- Identify database encryption keys.
- Identify user private data.
- Identify server-only secrets.
- Define attacker capabilities.
- Define acceptable recovery behavior.

Classification
- Classify public data.
- Classify ordinary private data.
- Classify credentials.
- Classify cryptographic keys.
- Classify high-impact secrets.
- Assign storage policy to each class.

Server secrets
- Never embed backend administrator credentials.
- Never embed payment-provider secret keys.
- Never embed database passwords.
- Never embed private server signing keys.
- Move privileged operations to backend infrastructure.
- Assume mobile binaries can be inspected.

Ordinary preferences
- Store theme.
- Store sort order.
- Store non-sensitive flags.
- Do not store passwords casually.
- Do not store long-lived credentials casually.
- Do not confuse private sandbox with secure key storage.

iOS Keychain
- Use Keychain for small secrets.
- Use Keychain for passwords where required.
- Use Keychain for tokens.
- Use Keychain for identities and keys where appropriate.
- Choose accessibility explicitly.
- Test locked-device behavior.
- Test background access.
- Test backup migration.
- Test device-only behavior.

Keychain accessibility
- Use restrictive accessibility where possible.
- Understand WhenUnlocked behavior.
- Understand AfterFirstUnlock behavior.
- Understand ThisDeviceOnly behavior.
- Avoid deprecated always-accessible policies.
- Document why background access is required.

Device migration
- Decide whether credential should move to a new device.
- Use device-only semantics for device identity where appropriate.
- Re-enroll device credentials after migration where appropriate.
- Do not assume migration behavior.
- Test real restore.

Secure Enclave
- Use for appropriate private-key operations.
- Keep private key hardware-bound where required.
- Do not expect every secret blob to belong in Secure Enclave.
- Define fallback for unsupported use cases.
- Handle key loss.
- Handle authentication policy changes.

iOS biometrics
- Decide whether authentication is required.
- Decide whether current biometric set matters.
- Handle enrollment changes.
- Handle Face ID / Touch ID unavailable.
- Provide device-credential fallback where product policy allows.
- Avoid endless authentication loops.

Android Keystore
- Use for cryptographic key material.
- Do not treat Keystore as a generic preference database.
- Generate keys through AndroidKeyStore where appropriate.
- Use key aliases deliberately.
- Restrict key purposes.
- Restrict algorithms.
- Restrict validity where required.
- Handle key invalidation.

Android hardware backing
- Check security level when it matters.
- Understand software-backed possibility.
- Understand trusted environment.
- Understand StrongBox.
- Do not assume StrongBox exists everywhere.
- Define product fallback.
- Test target device classes.

StrongBox
- Request only where security requirement justifies it.
- Detect unavailability.
- Avoid crashing when unavailable.
- Decide whether trusted environment is acceptable fallback.
- Document requirements.

Android authentication-bound keys
- Configure user-auth requirements deliberately.
- Decide authentication timeout.
- Decide biometric vs device credential policy.
- Handle UserNotAuthenticated.
- Handle permanently invalidated keys.
- Test enrollment changes.
- Test screen-lock removal.

AndroidX Security Crypto
- Check current platform documentation before using old tutorials.
- Be aware that EncryptedSharedPreferences is deprecated.
- Be aware that MasterKey convenience API is deprecated.
- Prefer a current supported design.
- Keep cryptographic key management separate from ordinary storage.

Application-private storage
- Use for ordinary private files.
- Use for ciphertext.
- Use for encrypted databases.
- Do not assume sandbox equals hardware-backed protection.
- Review backup behavior.
- Review debug extraction paths.

Encryption keys
- Never hard-code production encryption keys.
- Never store key beside ciphertext in plaintext.
- Generate keys securely.
- Protect keys through platform facilities.
- Rotate where required.
- Delete deliberately.
- Test lost-key behavior.

Authenticated encryption
- Protect confidentiality.
- Protect integrity.
- Use established algorithms.
- Avoid custom cryptography.
- Avoid fixed IV reuse.
- Use secure random values where required.
- Store nonce / IV according to algorithm requirements.
- Verify authentication tag before accepting plaintext.

Access tokens
- Prefer short lifetimes.
- Keep in memory when feasible.
- Persist only when product requires it.
- Limit scope.
- Remove on logout.
- Never log.
- Rotate / refresh according to protocol.

Refresh tokens
- Treat as high-value credentials.
- Use secure storage.
- Limit scope.
- Rotate where supported.
- Revoke server-side when appropriate.
- Remove on logout.
- Detect reuse where backend protocol supports it.
- Never send to analytics.

Passwords
- Avoid retaining after successful token exchange where possible.
- Never log.
- Never store plaintext in preferences.
- Never send to analytics.
- Avoid storing merely to implement automatic login.
- Prefer token-based session architecture.

API keys
- Distinguish public client identifier from secret.
- Do not pretend obfuscation makes a backend secret safe.
- Restrict any client-distributed API credential.
- Apply server-side quotas.
- Apply origin / application restrictions where provider supports them.
- Assume extracted client key can be copied.

Biometrics
- Use biometrics to authorize sensitive access.
- Do not call biometrics encryption by itself.
- Bind key use to authentication where appropriate.
- Preserve recovery path.
- Avoid biometric requirements that break background work.
- Test cancellation.
- Test lockout.

App lock
- Distinguish app-screen lock from authentication token security.
- Do not rely only on local UI gate.
- Protect underlying key or item where needed.
- Continue server-side authorization.
- Handle app snapshots.

Screenshots
- Review whether sensitive screens can appear in task switcher.
- Protect highly sensitive views where platform capabilities allow.
- Avoid displaying secrets unnecessarily.
- Mask passwords and recovery codes.
- Clear one-time secrets after use.

Clipboard
- Avoid copying credentials automatically.
- Avoid long clipboard retention where controllable.
- Warn user for sensitive recovery codes.
- Never use clipboard as secret storage.

Logs
- Never log Authorization header.
- Never log refresh token.
- Never log password.
- Never log private key.
- Never log database key.
- Redact sensitive request bodies.
- Review release logging.

Crash reporting
- Sanitize breadcrumbs.
- Sanitize custom metadata.
- Sanitize exceptions.
- Avoid attaching full request headers.
- Avoid attaching databases containing secrets.
- Review third-party crash SDK configuration.

Analytics
- Never send authentication tokens.
- Never send passwords.
- Never send private keys.
- Avoid sensitive personal fields.
- Review event parameters.
- Review user properties.
- Apply data minimization.

Debug builds
- Keep test credentials separate.
- Do not ship debug endpoints.
- Do not ship development certificates.
- Do not log production tokens.
- Disable insecure TLS overrides.
- Remove test backdoors.
- Verify release configuration.

Source control
- Do not commit production secrets.
- Scan repository.
- Rotate leaked secrets.
- Remove sensitive test accounts.
- Protect signing credentials.
- Keep environment-specific server secrets outside mobile source.

Memory
- Keep secrets in memory only as long as required.
- Avoid unnecessary copies.
- Do not build secret-heavy debug strings.
- Clear long-lived in-memory sessions on logout.
- Understand that application memory is not an absolute secure enclave.

Token lifecycle
- Issue token.
- Store appropriately.
- Use token.
- Refresh.
- Rotate.
- Revoke.
- Delete.
- Handle expiration.
- Handle compromised session.

Refresh rotation
- Preserve new token before discarding usable recovery state where protocol allows.
- Handle interrupted response.
- Handle duplicate retry.
- Handle token reuse.
- Define server grace behavior if required by architecture.
- Test crash during rotation.

Logout
- Revoke server session where supported.
- Delete refresh token.
- Delete access token.
- Clear in-memory credentials.
- Clear account-specific local data according to policy.
- Clear account-specific encryption keys where intended.
- Remove push-account mapping where required.
- Return to deterministic signed-out state.

Account switching
- Namespace credentials per account.
- Namespace encrypted data per account.
- Namespace local database state.
- Clear previous account memory.
- Prevent cross-account cache access.
- Test rapid account switching.

Server revocation
- Support logout revocation.
- Support stolen-device session revocation.
- Support password-change session policy.
- Support compromised refresh-token revocation.
- Support device removal.
- Apply authorization independently of local storage.

Backups
- Inventory what platform backs up.
- Decide what should migrate.
- Exclude device-bound ciphertext where appropriate.
- Exclude sensitive files where appropriate.
- Test backup rules.
- Test restore.
- Handle missing encryption key.
- Avoid silent data corruption.

iOS backup
- Understand Keychain accessibility migration behavior.
- Use ThisDeviceOnly where intentional.
- Reauthenticate when device-bound secret is missing.
- Test encrypted backup restore.
- Document recovery.

Android backup
- Review Auto Backup rules.
- Review SharedPreferences.
- Review internal files.
- Review databases.
- Exclude inappropriate encrypted artifacts.
- Test restore when Keystore key is absent.
- Use data extraction rules deliberately.

Encrypted database
- Separate data key from data.
- Protect key with platform mechanism.
- Authenticate ciphertext.
- Version encryption format.
- Plan migration.
- Plan key rotation.
- Handle lost key.
- Handle corrupted database.

Files
- Encrypt truly sensitive files where required.
- Store key separately.
- Restrict sharing.
- Avoid world-readable storage.
- Sanitize exported files.
- Remove temporary plaintext copies.
- Review external storage use.

Database key
- Generate securely.
- Never hard-code.
- Protect in Keychain / Keystore architecture.
- Define backup behavior.
- Define rotation.
- Define logout behavior.
- Define device migration.

Key rotation
- Assign key version.
- Create new key.
- Rewrap or reencrypt data.
- Verify migration.
- Retire old key.
- Keep rollback only when securely justified.
- Log version, not key material.

Key invalidation
- Catch platform errors.
- Distinguish auth required from permanent invalidation.
- Clear unusable session state.
- Reauthenticate user.
- Generate replacement key.
- Reencrypt recoverable data.
- Avoid crash loops.

Cryptographic erasure
- Understand that deleting a unique encryption key may make data unrecoverable.
- Use only when intentional.
- Ensure no backup copy of key remains if true erasure is required.
- Document recovery implications.

Background tasks
- Choose credentials that can be used while app is backgrounded.
- Avoid requiring interactive biometric auth for unattended sync.
- Use minimum required privilege.
- Refresh tokens carefully.
- Handle device-lock state.

Push notifications
- Do not place long-lived secrets in notification payloads.
- Do not assume notification content is private.
- Keep sensitive data fetch behind authenticated API.
- Review lock-screen exposure.

Rooted / jailbroken devices
- Treat as elevated risk.
- Do not rely on root detection as sole defense.
- Keep tokens short-lived.
- Limit privileges.
- Support revocation.
- Maintain server authorization.

Runtime instrumentation
- Assume client code can be inspected.
- Avoid permanent high-value secrets.
- Limit credential scope.
- Use server-side checks.
- Consider device-bound cryptographic proof for stronger scenarios.

Certificate pinning
- Do not confuse TLS pinning with local storage.
- Manage rotation carefully if used.
- Avoid breaking connectivity during certificate changes.
- Keep secure storage independent from transport assumptions.

Secure networking
- Use TLS.
- Validate certificates.
- Avoid disabling hostname verification.
- Avoid insecure development overrides in release.
- Never send credentials over plaintext transport.

Device-bound credentials
- Generate private key locally.
- Protect private key appropriately.
- Register public key server-side.
- Bind credential to account / device.
- Support revocation.
- Support device replacement.
- Handle key loss.

Least privilege
- Give tokens minimum scope.
- Separate read and administrative operations where useful.
- Limit token lifetime.
- Limit backend authorization.
- Do not let possession of one mobile token become global administrator access.

Session management
- Show active devices where useful.
- Allow user to revoke devices.
- Detect unusual token reuse where appropriate.
- Expire old sessions.
- Define password-change behavior.
- Define account-compromise response.

Testing
- Test fresh install.
- Test login.
- Test app restart.
- Test device lock.
- Test background operation.
- Test access-token expiration.
- Test refresh-token rotation.
- Test refresh failure.
- Test biometric cancellation.
- Test key invalidation.
- Test backup restore.
- Test logout.
- Test account switching.

Security review
- Inspect app package.
- Search binary strings.
- Search bundled configuration.
- Search logs.
- Search preferences.
- Search local database.
- Search cached files.
- Confirm privileged backend secrets are absent.

Recovery
- Define forgotten-device flow.
- Define lost-device flow.
- Define new-device enrollment.
- Define invalid-key recovery.
- Define corrupted encrypted-data recovery.
- Define support process.
- Avoid support agents requesting users to send raw tokens.

Documentation
- Document each secret.
- Document storage location.
- Document accessibility policy.
- Document backup behavior.
- Document migration behavior.
- Document rotation.
- Document deletion.
- Document server revocation.

Final review
- Is this value actually secret?
- What can an attacker do with it?
- Does it belong on the client at all?
- Is it a cryptographic key?
- Does it belong in Keychain?
- Does it belong in Android Keystore?
- Should Android store ciphertext outside Keystore?
- Does this credential need biometric authorization?
- Must it work in the background?
- Should it migrate to another device?
- Is backup behavior explicit?
- Is the token short-lived?
- Is refresh-token rotation supported?
- Can the server revoke it?
- Is the secret absent from logs?
- Is it absent from analytics?
- Is it absent from crash reports?
- Is it absent from source code?
- Is account switching isolated?
- Does logout remove local credentials?
- Does logout revoke server state where appropriate?
- Can the app recover if a key becomes invalid?
- Can encrypted data recover after device migration?
- Are privileged server secrets kept off the device?
- Does backend authorization remain effective even if local storage is compromised?

14. FAQ

What is the difference between Keychain and Keystore?

Apple Keychain can directly store small sensitive values such as passwords, tokens, certificates, and keys. Android Keystore primarily protects cryptographic keys and controls how those keys can be used. Android apps often use a Keystore-protected key to encrypt a token or database stored elsewhere.

Should refresh tokens be stored in Keychain or Keystore?

On iOS, a refresh token can be stored as a Keychain item using an accessibility policy appropriate to the application. On Android, a common design protects an encryption key with Android Keystore and stores the encrypted refresh token in app-private storage.

Should access tokens be stored permanently?

Not necessarily. If the application can keep a short-lived access token in memory and obtain a replacement from a securely protected refresh token, that reduces unnecessary persistent exposure.

Can I hard-code an API secret if I obfuscate the app?

Do not embed any credential that must remain secret from app users. Obfuscation may slow reverse engineering, but the distributed application still contains the information needed to use the credential.

Does biometric authentication make a token secure?

Biometrics can be part of an access-control policy for a Keychain item or cryptographic key. They do not automatically make arbitrary plaintext storage secure. The secret or key must still be stored through an appropriate mechanism.

What happens if a hardware-backed key becomes invalid?

The application should detect the condition and follow a documented recovery flow, typically clearing unusable session material, re-authenticating the user, creating a replacement key, and restoring only data that can be safely recovered.

Should secure data be backed up?

It depends on its role. User data may need migration, while a device-identity credential may intentionally remain tied to one physical device. Backup and migration behavior should be selected deliberately and tested on real restore flows.

Key terms (quick glossary)

Keychain
Apple's secure storage service for small sensitive items such as passwords, tokens, certificates, identities, and cryptographic keys.
Android Keystore
Android's protected cryptographic key facility for generating, storing, and using keys according to defined authorization policies.
Secure Enclave
Apple security hardware designed to protect sensitive cryptographic operations and selected device security functions.
StrongBox
An Android security-hardware profile that can provide stronger isolation for supported Keystore operations on devices that implement it.
Hardware-backed key
A cryptographic key whose sensitive key material and operations are protected by isolated security hardware rather than ordinary application memory.
Access token
A credential commonly used to authorize API requests for a limited period.
Refresh token
A longer-lived credential used to obtain replacement access tokens.
Key accessibility
A platform policy defining conditions under which stored secret material can be accessed, such as whether the device must be unlocked.
Device-bound credential
A credential designed to remain associated with one physical device rather than migrate freely between devices.
Biometric authorization
Using a successfully verified biometric identity to authorize access to an item or cryptographic operation.
Authenticated encryption
Encryption that protects both confidentiality and integrity so modified ciphertext can be detected.
Key rotation
Replacing an existing cryptographic key or credential with a new one according to a controlled migration process.
Key invalidation
A state in which a previously usable key can no longer perform the protected operation because a security condition or policy changed.
Cryptographic erasure
Making encrypted data unrecoverable by securely destroying the only key capable of decrypting it.
Least privilege
Limiting a credential to only the permissions and lifetime required for its intended operation.
Secure storage
Storage architecture designed to reduce unauthorized access to sensitive information using platform isolation, encryption, key management and controlled access policies.

Found this useful? Share this guide: