← Back to list

Session Management: Idle Timeouts and Step-Up Auth (Android)

Part 9 of our Android security series. Part 8 covered Credential Manager — getting the user signed in. This post covers what happens for…

Khizar Khan · 2026-08-19 12:46 · 0 claps · 3.0 min read
#android-development #mobile-security #cybersecurity #application-security #authentication
Open on Medium ↗
Wiki topics: BIZ · Business Strategy 📱 · Mobile Development 🔒 · Cybersecurity

Session Management: Idle Timeouts and Step-Up Auth (Android)

Part 9 of our Android security series. Part 8 covered Credential Manager — getting the user signed in. This post covers what happens for the rest of the session, until they sign out.

What it is, in one line

Session management is everything that happens after login: how long a session stays valid while the user does nothing, and when the app should ask for re-authentication even though they’re technically still signed in.

Why “just stay logged in forever” isn’t the answer

Mobile users expect long-lived sessions — nobody wants to log into their banking app every single time they open it. But “long-lived” and “no limits at all” aren’t the same thing. A phone left unlocked on a table, or lost with the app still open, is a real exposure window. The fix isn’t shortening every session — it’s being deliberate about which actions need a fresh check, even inside a session that’s otherwise still valid.

Idle timeout: lock the app, not just the account

An idle timeout doesn’t sign the user out of your backend — it locks the app itself after a period of inactivity, requiring a quick re-check (PIN, biometric) to resume:

class IdleTimeoutTracker(private val timeoutMs: Long = 5 * 60 * 1000) {
    private var lastActiveAt = System.currentTimeMillis()

    fun onUserInteraction() {
        lastActiveAt = System.currentTimeMillis()
    }
    fun isIdleTimedOut(): Boolean =
        System.currentTimeMillis() - lastActiveAt > timeoutMs
}

Hook this into Activity.onUserInteraction() and check it in onResume():

override fun onResume() {
    super.onResume()
    if (idleTracker.isIdleTimedOut()) {
        showLockScreen() // biometric or PIN re-entry, not a full re-login
    }
}

The right timeout length depends on what the app does — a few minutes for banking or health apps, longer for something low-stakes like a note-taking app. There’s no universal number; match it to what’s actually at risk if the phone is picked up unlocked.

Step-up auth: not every action deserves the same trust level

The idea behind step-up auth: being logged in is enough to browse, but certain actions — adding a new payee, changing a password, viewing a full card number — deserve a fresh, explicit check, even mid-session.

suspend fun performSensitiveAction(action: () -> Unit) {
    val freshAuth = requestBiometricConfirmation(
        title = "Confirm it's you",
        subtitle = "Required for this action"
    )
    if (freshAuth) {
        action()
    }
}

Tie this to the CryptoObject pattern from Part 7 wherever the action involves decrypting or signing something — the same principle applies: the check should gate the actual operation, not just a UI flag.

Good candidates for step-up auth: changing account credentials, adding a payment method, large transactions, viewing full sensitive records (not just masked previews), disabling security features like biometrics itself.

Server-side session expiry still matters

App-level idle locking is a UX layer — it doesn’t replace real session expiry enforced by your backend. The access token itself should still have a reasonable lifetime, checked server-side on every request, regardless of what the app’s lock screen is doing locally. Think of app-level locking as protecting the device in someone’s hand right now; server-side expiry protects against a token that leaked or was captured somewhere else entirely.

What to do when a session actually expires

fun handleSessionExpired() {
    clearTokensFromStorage() // from Part 6's secure storage
    clearInMemoryUserState()
    navigateToLogin(message = "Your session expired. Please sign in again.")
}

Clear tokens from wherever you stored them (DataStore + Tink from Part 6), not just from memory — a stale token sitting in storage is still a stale token.

Quick checklist

  • [ ] Idle timeout locks the app locally, sized to the sensitivity of what the app does
  • [ ] Sensitive actions require step-up auth, even mid-session
  • [ ] Step-up checks gate the actual operation (via CryptoObject where relevant), not just a UI boolean
  • [ ] Server-side token expiry enforced independently of any app-level lock screen
  • [ ] Expired sessions clear tokens from persistent storage, not just app memory

The one-line takeaway

Treat “signed in” as a spectrum, not a switch — idle timeouts protect against the phone in the wrong hands right now, and step-up auth makes sure the highest-value actions always get a fresh check, no matter how long the session’s been open.

Next up in the series: Token refresh & rotation — keeping sessions alive through flaky networks without opening a security hole.


메타데이터
post_id
a653fa39f711
slug
session-management-idle-timeouts-and-step-up-auth-android-a653fa39f711
url
https://medium.com/@khizarkhan8/session-management-idle-timeouts-and-step-up-auth-android-a653fa39f711
canonical_url
https://medium.com/@khizarkhan8/session-management-idle-timeouts-and-step-up-auth-android-a653fa39f711
author_url
https://medium.com/@khizarkhan8
status
ok
fetched_at
2026-08-21 01:45:42