Sessions the server keeps
With a stateless API, each request carries everything the server needs. With a stateful one, the server holds a session, the client holds identifiers that point at it, and the calls only work in the order the app makes them. This is why a request copied from the middle of a flow fails while the app keeps working.
Establishment
Trace the first calls the app makes after launch. They usually do more than authenticate.
- Login returns tokens and often a session identifier used by everything that follows.
- A device registration call binds the install to an account, and its response carries an identifier later requests must include.
- A bootstrap or configuration call returns feature flags, keys or endpoint hosts the rest of the app depends on.
- Some apps call an endpoint that opens a cart, an order or a session object, and every later request references that object.
Capture this sequence once and treat it as the entry point of any client you build. Skipping a step produces a failure that looks much like a bad signature, and the server's error message rarely distinguishes the two.
Ordering and dependencies
Build a dependency map rather than a list. For each request, note which values in its headers, query or body came from an earlier response. Those values are the edges of the graph.
- An identifier returned by a create call and passed to everything after it.
- A version or revision number returned by a read and echoed on the next write, so the server can reject a stale update.
- A token refreshed by one call and used by every call that follows.
- A cursor or sequence number that advances with each page.
Where the map branches, the app is tracking more than one workflow. Test each branch separately, because a screen may need two independent chains to reach a state before it can finish.
A traffic capture gives you a first draft of the map without reading any code. Read the sequence in order and mark every response value that appears again in a later request. The values that repeat are the ones your client has to carry forward, and the requests that produce them are the ones you cannot skip or reorder.
Cookie jars and persistence
Cookie based sessions behave differently from header based ones. The server sets a cookie at login, the client returns it on later requests, and the session ends when the cookie is replaced or cleared. HTTP clients that ignore cookies by default will authenticate and then appear to lose the session a request or two later.
Persistence changes behaviour across restarts. If the app writes cookies to disk and reloads them, and your client keeps them in memory only, a restart looks like a logout to the server. Match the app's storage behaviour, including the domain and path rules the server relies on. The same applies to tokens written to an encrypted preferences file: they survive a restart because the app put them somewhere that survives a restart.
Refresh without breaking the session
Token refresh interacts with ordering. A refresh usually replaces both the access token and the refresh token, so two concurrent requests that each notice an expired token can both trigger a refresh and invalidate one another. Serialise the refresh, and let waiting requests resume with the token the first refresh produced.
Session expiry is a different failure from token expiry. If a request keeps failing after a successful refresh, the server has ended the session and the client has to run the establishment sequence again. Distinguishing those two cases is what keeps a long running client alive.
Reconstructing the machine
Write the session down as an explicit state machine: the states, the requests that move between them, and the values carried across each transition. That representation can be tested. You can replay the establishment sequence, run a long sequence of calls, force an expiry and confirm the client recovers, which is more than a folder of saved requests can demonstrate. It also gives the next person a description of the flow that does not require reading the client code.
Related work
Reviewed 28 September 2026 · SReverse research desk