JSON Web Tokens are everywhere in mobile authentication, and they invite a few specific mistakes. The two that come up most: storing the token in insecure storage where it can be read off the device, and assuming the token's payload is private when it is just base64, readable by anyone. Add long-lived tokens and trusting the token on the client, and you have the common JWT failure pattern. None of it is hard to avoid once you know it. Here is what a JWT is, the mistakes mobile apps make, and how to handle them securely.
Short answer
A JSON Web Token (JWT) is a signed token, header, payload, and signature, used to authenticate requests, and mobile apps mishandle it in predictable ways. Per OWASP MASVS, the key points are: store JWTs in the Keychain or Keystore, not in UserDefaults, SharedPreferences, or other plain storage; treat the payload as readable, since it is base64-encoded, not encrypted, so never put secrets in it; keep access tokens short-lived with refresh; and never let the client be the authority, because the server must validate the token's signature on every request. Used this way, a JWT is a fine session mechanism; misused, it leaks or is trusted when it should not be.
What you should know
- Store JWTs securely: in the Keychain or Keystore, not plain storage.
- The payload is not secret: it is base64-encoded, readable by anyone.
- Keep tokens short-lived: short access-token expiry with refresh.
- The server validates: it must verify the signature on every request.
- The client is not the authority: do not make security decisions on an unverified token.
What is a JWT, and what is the trap?
A JWT is a compact, signed token whose contents are encoded, not encrypted. It has three parts, a header, a payload of claims, and a signature, joined and base64url-encoded, and the signature lets a server verify the token was issued by it and not tampered with. The trap is the encoding: because the payload is base64, not encrypted, anyone who has the token can decode and read its claims, so a JWT does not hide what is inside it. The signature provides integrity and authenticity, proof the token is genuine and unaltered, but not confidentiality. So the two things to internalize are that the payload is readable by anyone holding the token, and that the security comes from the server verifying the signature, not from the client trusting the token's contents.
What are the common JWT mistakes in mobile apps?
A handful of recurring errors. The table lists them.
| Mistake | Why it is a problem |
|---|---|
| Storing the token in plain storage | UserDefaults or SharedPreferences can be read off the device |
| Putting sensitive data in the payload | The payload is base64, readable by anyone with the token |
| Long-lived access tokens | A stolen token stays valid for a long time |
| Trusting the token on the client | A client decision can be bypassed; the server must verify |
| Not validating the signature server-side | An unverified token can be forged or altered |
The most common is insecure storage: a JWT in UserDefaults, SharedPreferences, or web storage can be extracted on a compromised or backed-up device, so it belongs in the Keychain or Keystore. Close behind is putting sensitive data in the payload, which is exposed because the payload is merely encoded, and trusting the token on the client to gate access, when only the server validating the signature actually enforces anything.
How do you handle JWTs securely?
Store them securely, keep them short, and let the server be the authority. Store access and refresh tokens in the Keychain or Keystore so they are not readable from plain storage, and transmit them only over HTTPS. Keep access tokens short-lived and use a refresh token to obtain new ones, so a stolen access token has a small window, and store and rotate the refresh token carefully. Put no sensitive data in the payload, since it is readable, only the claims needed for authorization. On the server, validate the signature on every request, check expiry and the expected claims, and never accept a token without verifying it, which is also where you guard against signature-algorithm tricks. And do not have the client make security decisions based on the token's contents alone; the client can read claims for display, but enforcement happens server-side. The token is a credential to protect and verify, not a source of truth the client can trust.
What to watch out for
The first trap is storing the JWT in UserDefaults, SharedPreferences, or AsyncStorage, where it can be extracted; use the Keychain or Keystore. The second is putting sensitive data in the payload, which is base64-encoded and readable by anyone holding the token. The third is the client trusting the token to grant access, when only server-side signature validation enforces it. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the compiled APK, AAB, or IPA against OWASP MASVS and surfaces insecure token storage and how the app handles sensitive data, so you can confirm JWTs are stored securely before you ship. Validating signatures and keeping tokens short-lived is work on the token issuer and your server.
What to take away
- A JWT is a signed token whose payload is base64-encoded, not encrypted, so anyone with the token can read its claims, while the signature provides integrity, not confidentiality.
- Store JWTs in the Keychain or Keystore, not plain storage, transmit them over HTTPS, and keep access tokens short-lived with refresh.
- Put no sensitive data in the payload, and never let the client be the authority; the server must validate the signature on every request.
- Use a pre-submission scan such as PTKD.com to confirm tokens are stored securely rather than in plain storage.



