Security

    Secure token storage and refresh in mobile apps

    A 2026 view of secure token handling where access and refresh tokens are stored in the Keychain or Keystore, with refresh token rotation detecting reuse and revoking the family

    After a user signs in, your app holds tokens: a short-lived access token it sends with each request, and usually a longer-lived refresh token it uses to get new access tokens without making the user log in again. Those tokens are the keys to the user's session, so where you store them and how you handle their lifecycle is a real security decision. Store them in the wrong place and a compromised device or backup leaks them; handle refresh badly and a stolen refresh token grants long-term access. Here is how to store tokens securely and manage the access-and-refresh lifecycle so a leak is contained.

    Short answer

    Tokens should be stored in the platform's secure storage, the iOS Keychain or Android Keystore-backed storage, never in plaintext locations like UserDefaults, SharedPreferences, or files. Per OWASP, access tokens should be short-lived to limit the exposure window, while the longer-lived refresh token is high-value and warrants extra care, including refresh token rotation, issuing a new refresh token on each use, invalidating the old one, and detecting reuse to catch theft. Transmit tokens only over TLS, keep them out of logs, URLs, and analytics, clear them on logout and revoke server-side, and prefer sender-constrained tokens where available so a stolen token is not usable elsewhere. The aim is that tokens are protected at rest, short-lived where possible, and revocable, so a leak is limited.

    What you should know

    • Store tokens in secure storage: Keychain or Keystore, not plaintext.
    • Keep access tokens short-lived: to limit the exposure window.
    • The refresh token is high-value: protect it and rotate it.
    • Rotate refresh tokens and detect reuse: to catch token theft.
    • Clear on logout and revoke server-side: do not just delete locally.

    Where do you store tokens?

    In the platform's secure storage, not in convenient plaintext stores. Tokens are secrets, so they belong in the iOS Keychain or in Android storage backed by the Keystore, which protect them with the device's secure facilities, rather than in places that store data in plaintext. The common mistake is putting a token in UserDefaults on iOS or SharedPreferences on Android, or in a plain file, all of which keep it readable in plaintext where it can be recovered on a compromised or jailbroken device and swept into backups. So the first decision is simply location: a token is a credential, and credentials go in secure storage. Beyond where they rest, tokens must also be handled carefully in transit and in passing: send them only over TLS, never put them in URLs, where they can end up in logs and history, and keep them out of application logs and analytics, since a token that leaks anywhere is a token an attacker can use. Secure storage protects the token at rest; disciplined handling keeps it from leaking elsewhere.

    How do access and refresh tokens differ, and what is rotation?

    By lifetime and role, which shapes how you protect each. The table summarizes.

    AspectAccess tokenRefresh token
    LifetimeShort-livedLonger-lived
    UseSent with each requestExchanged for new access tokens
    Exposure windowLimited by short lifetimeLarger, so higher value
    RotationReissued frequently by designRotated on each use, old one invalidated
    Theft detectionLimited by expiryReuse of an old token signals theft

    An access token is short-lived and accompanies each request, so keeping its lifetime short limits how long a leaked one is useful, expiry does much of the work of containing exposure. A refresh token lives longer and is exchanged for new access tokens, which makes it higher value: a stolen refresh token can grant continued access, so it deserves more protection. Refresh token rotation addresses this: each time a refresh token is used, the server issues a new one and invalidates the old, so a refresh token is single-use. The security payoff is theft detection, if an old, already-rotated refresh token is presented again, that signals it was stolen and replayed, and the server can revoke the whole token family, cutting off the attacker and the legitimate client so the user re-authenticates. So the two token types call for different handling: short lifetimes for access tokens, and rotation with reuse detection for refresh tokens.

    How do you handle tokens securely across their lifecycle?

    Protect them at rest, in transit, and across issuance, refresh, and revocation. Store both tokens in secure storage, keep access-token lifetimes short, and use refresh token rotation with reuse detection so a stolen refresh token is caught and the family revoked. Transmit tokens only over TLS and never log them, embed them in URLs, or send them to analytics. On logout, clear the tokens from secure storage locally and revoke them server-side, so the session genuinely ends rather than the tokens remaining valid; the server, as the authority, must be able to revoke a session, and you should rely on that rather than assuming a local delete is enough. Scope tokens to least privilege so a leaked token grants only what it must, and prefer sender-constrained or device-bound tokens where your platform and provider support them, so a token stolen from one device cannot be used from another. Keep verification on the server: the backend validates every token, since the app is one client and an attacker can present a token directly. The principle is that tokens are protected secrets with a managed lifecycle, short-lived, rotated, revocable, and bound where possible, so that even a leaked token has limited value and a short life.

    What to watch out for

    The first trap is storing tokens in UserDefaults, SharedPreferences, or a plain file, where they sit in plaintext and leak from a compromised device or backup; use secure storage. The second is long-lived access tokens and refresh tokens without rotation, so a single leak grants lasting access; shorten access lifetimes and rotate refresh tokens with reuse detection. The third is logout that only deletes locally without server-side revocation, and tokens leaking through URLs, logs, or analytics. Token handling spans app and server, so a pre-submission scan such as PTKD.com (https://ptkd.com), which reads the binary against OWASP MASVS, surfaces how your app stores data and handles authentication, flagging tokens kept insecurely, while rotation and revocation are yours to implement on the backend.

    What to take away

    • Store access and refresh tokens in the platform's secure storage, the Keychain or Keystore-backed storage, never in plaintext locations like UserDefaults, SharedPreferences, or files.
    • Keep access tokens short-lived to limit exposure, and protect the higher-value refresh token with rotation, issuing a new one on each use and detecting reuse to catch theft and revoke the family.
    • Transmit tokens only over TLS, keep them out of URLs, logs, and analytics, clear them on logout and revoke server-side, scope to least privilege, and prefer device-bound tokens where supported.
    • Use a pre-submission scan such as PTKD.com to surface insecure token storage and authentication handling, and implement rotation and revocation on the backend.
    • #tokens
    • #refresh-token
    • #secure-storage
    • #authentication
    • #token-rotation
    • #owasp-masvs
    • #mobile

    Frequently asked questions

    Where should a mobile app store auth tokens?
    In the platform's secure storage: the iOS Keychain or Android storage backed by the Keystore, which protect secrets with the device's secure facilities. Tokens are credentials, so they belong there, not in plaintext stores. The common mistake is putting a token in UserDefaults on iOS or SharedPreferences on Android, or in a plain file, all of which keep it readable in plaintext where it can be recovered on a compromised or jailbroken device and swept into backups. Location is the first decision: a token is a secret and goes in secure storage.
    What is refresh token rotation?
    It is issuing a new refresh token each time one is used and invalidating the old, so a refresh token is effectively single-use. The security payoff is theft detection: if an old, already-rotated refresh token is presented again, that signals it was stolen and replayed, and the server can revoke the whole token family, cutting off both the attacker and the legitimate client so the user re-authenticates. Rotation matters because the refresh token is longer-lived and high-value, since it can be exchanged for new access tokens, so detecting its theft limits the damage.
    Why keep access tokens short-lived?
    Because a short lifetime limits how long a leaked access token is useful. The access token accompanies each request, so it is exposed often, and if one leaks, a short expiry means it stops working quickly, doing much of the work of containing the exposure without needing to detect the leak. The refresh token then provides continuity by obtaining new access tokens, which is why it gets extra protection and rotation. Short access lifetimes plus a protected, rotated refresh token give you both convenience and a limited window for any single leaked access token.
    What should happen to tokens on logout?
    Clear them from secure storage locally and revoke them server-side. Deleting tokens only on the device is not enough, because the tokens may remain valid on the server until they expire, so a copy obtained before logout could still be used. The server is the authority on sessions, so it must be able to revoke them, and logout should trigger that revocation in addition to the local clear. That way the session genuinely ends. Combine this with short access lifetimes and refresh rotation so revocation and expiry together close out access promptly.
    How can a scan help with token handling?
    Token handling spans the app and the server, so part is client-side storage and part is server-side lifecycle. A pre-submission scan such as PTKD.com reads the binary against OWASP MASVS and surfaces how your app stores data and handles authentication, flagging tokens kept in insecure storage like UserDefaults or SharedPreferences so you can move them to the Keychain or Keystore. The lifecycle controls, short access lifetimes, refresh token rotation with reuse detection, and server-side revocation, are implemented on the backend, where the session authority lives.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free