Build the mental model
The core mobile auth flow: user logs in -> app sends credentials to the auth server -> server responds with a token -> app stores it in secure storage and attaches it to API requests.
- Access Token — short-lived, sent with each API request
- Refresh Token — longer-lived, used to get a new access token without a full re-login
- Session Token — an active session tracked directly by the server
- JWT is common, but no single token format is universal
OAuth/social login adds a delegated flow — the app redirects to a provider, the user approves there, and the app/backend receives an authorized session; this handoff returns through a deep link with its own security considerations.
Biometric unlock does not replace backend authentication
Biometric unlock protects local app access — it does not replace backend authentication. Face ID or a fingerprint confirms who is holding the device; it does not, by itself, issue or validate the server-side tokens an API relies on.
- Access Token
- A typically short-lived token sent with each API request, letting the server recognize the request as authenticated.
- Refresh Token
- A longer-lived token used to obtain a new access token once the old one expires, without forcing a full re-login.
MOBILE AUTHENTICATION ARCHITECTURE
----------------------------------
MOBILE AUTHENTICATION ARCHITECTURE
-----
Mobile App --login--> Auth Server
|
v
Session / Access Token
|
v
Secure Local Storage
|
v
Authenticated API Requests
OAuth / social login branch:
Mobile App --redirect--> Provider (Apple/Google)
|
User Approves
|
v
App/Backend gets Authorized SessionConnect it to a real scenario
The trickiest part of mobile authentication isn't the initial login — it's keeping the session alive correctly afterward, checking token state before every request.
- Not checking expiration silently sends doomed requests and shows confusing errors
- Refreshing too eagerly wastes calls to the auth server for no benefit
- Never detecting an expired refresh token can trap a user in a loop of failing requests
OAuth callbacks return control through a deep link, so the app must validate that the authorization actually corresponds to the request it made.
Biometric unlock does not replace backend authentication
Face ID or a fingerprint protects local device/app access — it does not, by itself, issue or validate the server-side access/refresh tokens an API request relies on. It is not a replacement for the full mobile authentication architecture.
Try the working example
function decideAuthAction(session, now) {
const { accessTokenExpiresAt, refreshTokenExpiresAt } = session;
if (now < accessTokenExpiresAt) {
return "proceed with current access token";
}
if (now < refreshTokenExpiresAt) {
return "refresh access token, then proceed";
}
return "require full re-login (refresh token also expired)";
}
const nowTs = 1000000;
const validSession = { accessTokenExpiresAt: nowTs + 100000, refreshTokenExpiresAt: nowTs + 500000 };
const expiredAccessValidRefresh = { accessTokenExpiresAt: nowTs - 1000, refreshTokenExpiresAt: nowTs + 500000 };
const bothExpired = { accessTokenExpiresAt: nowTs - 1000, refreshTokenExpiresAt: nowTs - 500 };
console.log("Valid session:", decideAuthAction(validSession, nowTs));
console.log("Expired access, valid refresh:", decideAuthAction(expiredAccessValidRefresh, nowTs));
console.log("Both tokens expired:", decideAuthAction(bothExpired, nowTs));Valid session: proceed with current access token
Expired access, valid refresh: refresh access token, then proceed
Both tokens expired: require full re-login (refresh token also expired)
A still-valid access token proceeds immediately, an expired access token with a good refresh token triggers a refresh first, and only when both are expired does the function require a full re-login.5-minute try-it
Add a third token field, `isRevoked`, to the session object and update `decideAuthAction` so a revoked token always forces a full re-login even if it hasn't technically expired yet — then test it against a valid-looking but revoked token.
One important caution
Assuming JWT is the only token format and ignoring that session/refresh tokens are distinct concepts
Treating biometric unlock as a replacement for backend authentication and skipping server-side token validation entirely
OAuth — Wikipedia — How Mobile Apps Work