feat(auth): persist the trust token returned by the SSO exchange #29

Merged
whitlocktech merged 1 commits from feat/sso-trusted-device into main 2026-07-28 06:11:32 +00:00
Member

What & why

Pairs with website#108, which makes "trust this device" actually work for SSO sign-ins. Two things reach this device when the user ticks the box on the TOTP form:

  1. The rg_trust cookie in the Custom Tab. Custom Tabs share the system browser's cookie jar, so that alone makes the next SSO sign-in skip the TOTP step — no app change needed for that half.
  2. A trustToken in the /auth/mobile/sso/exchange response — which is what this PR stores. That covers the app's native password login on the same device, which already reads the token back out of TrustTokenStore and replays it as X-Trust-Token.

MobileTokenResponse already carried trustToken (the native login path has always persisted it) — SsoAuthManager simply dropped it on the floor. Now it saves it, scoped to the signed-in username exactly like AuthRepository.login does, so it is never replayed for a different account on a shared device; and saves it before onSignedIn so a process death mid-callback can't lose it.

How it was tested

  • 2 new cases in SsoAuthManagerTest: the token is persisted and scoped to its owner (tokenFor("mallory") is null); an absent token leaves the store untouched. Uses an in-memory FakeTrustTokenStore matching the file's existing fake style.
  • Full unit suite green: 266 tests, 0 failures (./gradlew testDebugUnitTest --rerun-tasks -Pksp.incremental=false).

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • AI tools were used. Tool(s): Claude Code (Opus 5). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.
## What & why Pairs with **website#108**, which makes "trust this device" actually work for SSO sign-ins. Two things reach this device when the user ticks the box on the TOTP form: 1. **The `rg_trust` cookie in the Custom Tab.** Custom Tabs share the system browser's cookie jar, so that alone makes the next **SSO** sign-in skip the TOTP step — no app change needed for that half. 2. **A `trustToken` in the `/auth/mobile/sso/exchange` response** — which is what this PR stores. That covers the app's **native password** login on the same device, which already reads the token back out of `TrustTokenStore` and replays it as `X-Trust-Token`. `MobileTokenResponse` already carried `trustToken` (the native login path has always persisted it) — `SsoAuthManager` simply dropped it on the floor. Now it saves it, scoped to the signed-in username exactly like `AuthRepository.login` does, so it is never replayed for a different account on a shared device; and saves it **before** `onSignedIn` so a process death mid-callback can't lose it. ## How it was tested - 2 new cases in `SsoAuthManagerTest`: the token is persisted and scoped to its owner (`tokenFor("mallory")` is null); an absent token leaves the store untouched. Uses an in-memory `FakeTrustTokenStore` matching the file's existing fake style. - Full unit suite green: **266 tests, 0 failures** (`./gradlew testDebugUnitTest --rerun-tasks -Pksp.incremental=false`). ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [x] AI tools were used. Tool(s): `Claude Code (Opus 5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude added 1 commit 2026-07-28 06:03:30 +00:00
feat(auth): persist the trust token returned by the SSO exchange
All checks were successful
PR Checks / android-build (pull_request) Successful in 7m55s
b10dd444b3
Pairs with website feat/sso-trusted-device, which makes "trust this device" work
for SSO sign-ins. Two things reach this device when the user ticks the box:

  1. The rg_trust COOKIE in the Custom Tab. Custom Tabs share the system
     browser's cookie jar, so that alone makes the next SSO sign-in skip the
     TOTP step — no app change needed for that half.
  2. A trustToken in the /auth/mobile/sso/exchange response, which is what this
     commit stores. That covers the app's NATIVE password login on the same
     device, which reads the token back out of TrustTokenStore and replays it as
     X-Trust-Token.

MobileTokenResponse already carried trustToken (the native login path has always
persisted it) — SsoAuthManager simply dropped it on the floor. Save it scoped to
the signed-in username, exactly like AuthRepository.login does, so it is never
replayed for a different account on a shared device; and save it before
onSignedIn so a process death mid-callback can't lose it.

Tests: 2 new cases in SsoAuthManagerTest (token persisted + scoped to its owner;
absent token leaves the store untouched), with an in-memory FakeTrustTokenStore
matching the file's existing fake style. Full unit suite green: 266 tests.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech approved these changes 2026-07-28 06:07:38 +00:00
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-07-28 06:07:45 +00:00
whitlocktech merged commit 4fe7a7e2a3 into main 2026-07-28 06:11:32 +00:00
whitlocktech deleted branch feat/sso-trusted-device 2026-07-28 06:11:32 +00:00
Sign in to join this conversation.
No description provided.