Skip to content

Keep the sign-in attempt when the phone kills the app mid sign-in - #168

Merged
simonhamp merged 1 commit into
mainfrom
fix/sign-in-survives-restart
Nov 6, 2026
Merged

simonhamp merged 1 commit into
mainfrom
fix/sign-in-survives-restart

Conversation

@simonhamp

Copy link
Copy Markdown
Member

A user on a Xiaomi Redmi Note 12 4G could never sign in. Every time the browser came back, the app said "that sign-in didn't start on this phone". Their video shows the splash screen on the way back, so MIUI had killed the app while the auth browser was open. The callback then landed in a fresh process with no attempt in memory, and the state check had nothing to match.

SignIn now also keeps the attempt's verifier and state in the Keychain (Keystore on Android) under devnull.sign-in. When there's no attempt in memory, take() falls back to that copy. It's deleted as soon as it's taken, whatever the answer was, and anything older than ten minutes is ignored. The state check in onboarding is unchanged, so callbacks this phone didn't start are still rejected. If the Keychain won't take it, sign-in works in memory as before.

This undoes the old rule that the verifier is never written down, but only for the Keychain, and only until the callback arrives. The old test for that rule now checks that the Keychain is the only place it goes and that it's deleted afterwards. New tests cover a sign-in finishing after a restart, a wrong state after a restart, and an attempt that's too old. The restart test fails without the fix.

Not tried on a device yet. To reproduce on Android: start sign-in, run adb shell am kill <app id> while the browser is open, then finish signing in. It should land on the Log.

Screenshots

  • No visible change

🤖 Generated with Claude Code

A Redmi Note 12 4G always got "that sign-in didn't start on this phone".
MIUI kills the app while the auth browser is in front, so the callback
started a fresh process that had no attempt in memory to check the state
against.

The attempt's verifier and state are now also kept in the Keychain (the
Keystore on Android) until the callback takes them. A fresh process falls
back to that copy. It's deleted once used and ignored after ten minutes,
and the state is checked as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simonhamp
simonhamp merged commit 83d857d into main Nov 6, 2026
1 of 2 checks passed
@simonhamp
simonhamp deleted the fix/sign-in-survives-restart branch November 6, 2026 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant