A shared credential cache, one file with no name on it, and a second user who could never finish logging in. On the difference between a cache that works and a cache that knows whose it is.

oauthmulti-usersdkdebuggingindie dev

Two children, one tablet

LittleStory keeps a separate profile for each child — a name, a photo, a few seconds of their own recorded voice. My daughter's stories and her cousin's stories live in the same app on the same tablet, and neither one should ever come back in the other's voice. That promise is made quietly, in a settings screen nobody reads, and it is the reason I spent most of last week staring at a credential file that belonged to someone else.

The thing I was actually fixing was a trading dashboard. It allows more than one person to log in, and each person connects their own brokerage account. Sign in as A, connect, sign out, sign in as B — and B could never finish authorizing. No error message. Just a browser window that opened and then sat there until something, somewhere, gave up.

The cache that assumed one user

The vendor's SDK keeps its credentials in a single file at a fixed path. One file, one machine, one assumed person. When A connects, that file holds A's token. When B tries, the SDK finds a token sitting there and decides the session is already fine — so the flow B actually needed never starts. Or it decides nothing is cached, tries to open a browser to authorize, and waits. A server process can never satisfy that wait, because nobody is sitting in front of it to click Allow.

The fix was not clever. Before connecting B, write B's stored token into that path so the check passes immediately. After connecting, read the file back — the SDK may have quietly refreshed the token on its own — and write the fresh value into encrypted storage. Two small moves wrapped around a file that was never designed to hold more than one identity.

What the vendor's own docs would have told me

When I finally read the official OAuth documentation, three things in my implementation were simply wrong: I asked users to paste in a client ID that the API can register for them, I pointed at the wrong regional domain, and I put a 30-second timeout on a step where a real human needs one to two minutes to read a consent screen and decide.

None of it was exotic. All of it was knowable before I wrote a line. The cache, too: shared, global, never namespaced. That is fine right up until the day a second person shows up.

One person, one slot

There is a quieter version of this bug waiting in every app that stores something personal. If LittleStory had kept a single shared slot for voice, the second child would open the app and hear the first child reading to them — and nothing would look broken. No crash, no red text. Just the wrong person, in the right place.

That is most of the job, really. One person's data, kept for that person only, in a place no other session can reach.

← Back to all posts