← All writing
Engineering·Aug 25, 2026·5 min read

Session expiry is a design problem, not a bug

A JWT with a 15-minute expiry is a security decision. What happens to the user when it fires mid-form is a product decision nobody made on purpose.

H

Hammad Iqbal

Software Engineer

Short-lived access tokens are the right call for security. Nobody disagrees with that in the design review. The disagreement shows up three weeks later, when a support ticket says a user lost twenty minutes of form input because their token expired mid-session and the app just... logged them out.

In brief
  • Access tokens should expire fast; refresh tokens are what keep users from feeling it.
  • A 401 mid-request isn't the same failure everywhere in the app — treat it differently depending on what's at stake.
  • Test logout by opening two tabs, not one.

The silent refresh has to actually be silent

The pattern is well known: catch the 401, use the refresh token to get a new access token, retry the original request, and the user never sees any of it. What's easy to miss is the retry step — a request interceptor that refreshes the token but doesn't replay the failed request just moves the visible failure one step later, and now it's harder to debug because the token looks valid by the time anyone checks it.

Not every 401 deserves the same response

A 401 on a background poll — checking for new notifications, say — should refresh quietly and move on. A 401 on a form submit the user just spent ten minutes filling out needs the refresh to happen first, the submit to be retried automatically, and only a full logout if the refresh itself fails. Routing every 401 through the same 'log the user out' handler is simpler to write and worse for anyone who was mid-task when it fired.

  • Background requests: refresh silently, retry, no user-visible signal
  • User-initiated actions: refresh, retry the original request, preserve the input either way
  • Refresh itself failing: that's the only case that should force a logout

Multi-tab logout is the case nobody tests

Logging out in one tab while a second tab is open on the same session is a real scenario, not an edge case — most people have the app open in more than one tab by the second week of using it. Without a `BroadcastChannel` or a shared storage event syncing auth state across tabs, the second tab keeps making requests with a token that's already been invalidated, and the failure mode users report is 'random logouts' that have nothing to do with expiry.

Takeaway

Treat token expiry as a UX surface, not just an auth implementation detail. The refresh logic is invisible when it works — which is exactly why it needs to be tested on purpose.

Have a project this kind of thinking applies to?

Tell me what you're building — I read every message myself.

Available for new projects

4+

Years exp.

8+

Projects shipped

<6h

Avg. reply time

Let's build something

Tell me about your project.

Share what you're building, your timeline, and the best way to reach you.