When using JWTs or OAuth tokens, one challenge is:
“What happens when the access token expires?”
Answer: Use a Refresh Token.
🧭 Why Refresh Tokens Exist
-
Access tokens should be short-lived (e.g., 15 mins).
-
But logging the user in every 15 mins? 🤯 No thanks.
-
So we issue a long-lived refresh token to get new access tokens silently.
🔄 How Refresh Tokens Work (Simplified Flow)
-
User logs in
-
Server returns:
-
access_token
(expires soon) -
refresh_token
(expires later or never)
-
-
-
Client uses access_token for API calls.
-
When it expires, client sends:
POST /token/refresh Authorization: Bearer <refresh_token> ```
-
Server verifies it, and returns a new
access_token
.
🛡️ Secure Refresh Token Strategy
🔐 Best Practice | Why |
---|---|
Store refresh tokens securely (e.g., EncryptedSharedPreferences on Android) | Prevent token theft |
Rotate refresh tokens on every use | Prevent reuse attacks |
Invalidate old refresh tokens immediately after rotation | Avoid replay |
Bind token to device / IP / fingerprint | Add extra layer of safety |
Don’t send refresh tokens to 3rd-party frontends | They’re long-lived and sensitive |
🔄 Token Rotation (Modern Best Practice)
Each time a refresh token is used, issue a new one and invalidate the old.
-
Prevents replay attacks (stealing and reusing a refresh token).
-
Some services (e.g., Auth0, Okta) do this by default.
plaintext
CopyEdit
User → refreshes → gets new access + new refresh Old refresh → marked invalid
🔥 Android-Specific Notes
-
Store access/refresh tokens in:
-
EncryptedSharedPreferences (recommended)
-
Jetpack Security Crypto Library
-
-
NEVER store in plaintext.
-
Always prefer using AppAuth or FirebaseAuth over rolling your own flow.
🧠 Gotchas
-
Don’t use the same refresh token forever. Rotate.
-
Handle refresh token expiration (e.g., user logs in again).
-
Monitor refresh usage for abuse detection.