How to Test Session Expiry and Refresh

Session expiry is the boundary between "logged in" and "logged out." Handling it badly means users get dumped to login mid-action, or stay logged in long after they should be out. Testing it requires

February 08, 2026 · 3 min read · How-To Guides

Session expiry is the boundary between "logged in" and "logged out." Handling it badly means users get dumped to login mid-action, or stay logged in long after they should be out. Testing it requires patience (sessions take time to expire) or careful mocking. This guide covers both approaches.

What to test

Active session

  1. Session valid during active use
  2. Token refresh happens silently before expiry
  3. User never sees unexpected logout during active use

Idle session

  1. Idle timeout enforced after configured period (e.g., 30 minutes for banking)
  2. Warning before timeout ("Session expires in 1 minute")
  3. "Stay logged in" option extends session
  4. Auto-logout if user does not respond

Background / foreground

  1. App backgrounded → foregrounded within limit → session still valid
  2. App backgrounded > limit → session expired on foreground

Explicit actions

  1. Logout immediately invalidates session
  2. "Log out all devices" invalidates all
  3. Password change invalidates current sessions (or keeps active — per policy)
  4. Account deletion invalidates all

Refresh flow

  1. Access token near expiry → silent refresh
  2. Refresh token valid → get new access token
  3. Refresh token expired / revoked → log user out cleanly
  4. Race: two requests simultaneously trigger refresh → only one refresh happens

Edge cases

  1. Clock skew between client and server → refresh still works within tolerance
  2. Network failure during refresh → retry or show auth error
  3. User logged in on multiple devices — refresh independent per device
  4. Session expired while in middle of form — data preserved if possible
  5. Server rotates secret → all tokens invalidated → users re-auth

Security

  1. Session timeout appropriate to sensitivity (5 min banking, 30 min normal)
  2. Cannot use expired token for new requests
  3. Refresh token not usable as access token
  4. Token revocation effective within acceptable window
  5. Session fixation prevented (new session on login)

UX

  1. Expiry not surprising — user warned or expected
  2. Re-login after expiry preserves user's intended destination (deep link)
  3. Error message clear ("Session expired, please log in")
  4. Not dumped to home screen without context

Testing approach

Manual

Automated

End-to-end


def test_token_refresh(page, api_mock):
    page.goto("/dashboard")
    # Simulate token near expiry
    api_mock.expire_token_at(30)  # 30 seconds from now
    time.sleep(30)
    # Trigger any authenticated action
    page.click("text=Refresh data")
    # Assert request succeeded (refresh happened silently)
    expect(page.locator(".data")).to_be_visible()

Fix patterns

Silent refresh

Interceptor checks token expiry before each request. If near expiry, refresh first, then proceed.

Queue during refresh

All requests queue while refresh in progress. After refresh, all use new token.

Graceful expiry UI

If user-initiated action encounters expired session:

  1. Save the intended action
  2. Prompt for login
  3. After login, replay action
  4. Show success / error

Multi-device awareness

User logged in on N devices. Logout on device A should invalidate device A's token. If security-critical, option to invalidate all.

How SUSA tests session handling

SUSA's login phase establishes a session. Subsequent steps use it. If session expires mid-exploration, SUSA detects (401 responses, login screen appearance) and reports it as an issue or re-authenticates if configured.


susatest-agent test myapp.apk --steps 200 --re-auth-on-expiry

Can configure a short session for deliberate expiry test.

Common production bugs

  1. Refresh race condition: two refreshes happen simultaneously, second invalidates first → user logged out
  2. Clock skew between client and server causes false expiry — refresh rejected as "too early"
  3. Refresh token has same or longer life as access token — defeats the point
  4. Password change does not invalidate sessions — compromised session persists
  5. Silent refresh fires on every request (no caching) — performance hit

Session management is foundational. Get it right; users never think about auth. Get it wrong; they contact support.

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free