Skip to content
This repository was archived by the owner on Oct 5, 2026. It is now read-only.

Make the kill switch stop the writes, not only the session - #40

Merged
ParallelEntrepreneur merged 1 commit into
mainfrom
fix/disabled-account-writes
Sep 7, 2026
Merged

ParallelEntrepreneur merged 1 commit into
mainfrom
fix/disabled-account-writes

Conversation

@ParallelEntrepreneur

Copy link
Copy Markdown
Contributor

Closes #37.

A one-place fix, and it is one place only because the shared step moved into auth-core::federated in #39. Before that it would have been three copies of the same edit — which is the argument that change was making.

What was wrong

users.status was already honoured where it counts: issue refuses a disabled account, and no session was ever handed out. But complete carried out the linking outcome first, and every branch of it writes:

  • Known records a login timestamp on the identity;
  • AutoLinked inserts a new identity row and has the caller announce it.

So an account someone had switched off went on accruing rows and events on every sign-in attempt, and the kill switch stopped short of the thing it is for.

The fix

The status is read before the outcome is acted on, in one place every federated method goes through. NewUser is exempt because it cannot name an account that already exists; the other outcomes all resolve to a user id, which is what makes the check possible this early.

Same shape as the passkey sign-count bug from #13/#14 — a write that happens before the check that should have refused the request — and far lower impact, which is why it was filed rather than rushed.

Tests

Two, both verified to fail with the fix removed:

  • a repeat sign-in on a disabled account leaves last_login_at alone;
  • a verified-address match onto a disabled account inserts no identity.

The first passed for the wrong reason on its first attempt. I advanced the test clock an hour to make the timestamp visibly different, which expired the fake's ID token — so the callback failed at token verification and never reached the linking rules at all. It now advances a minute, and the comment says why. That is the third time in this repo a test has passed while proving nothing, so the check-that-it-fails step is earning its cost.

329 workspace tests, clippy clean, rustfmt clean, wasm32 clean, cargo deny passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01V8K9TBtmnf29dV6uEP5oM3

Closes #37, and it is a one-place fix only because the shared step moved
into `auth-core::federated` in #39. Before that it would have been three
copies of the same edit, which is the argument that change was making.

`users.status` was already honoured where it counts: `issue` refuses a
disabled account and no session was ever handed out. But `complete`
carried out the linking outcome *first*, and every branch of it writes.
A disabled account signing in with Google, Apple or Facebook still
recorded a login on its identity; a verified-address match still inserted
a new identity row and had the caller announce it. So an account someone
had switched off went on accruing rows and events on every attempt, and
the switch stopped short of the thing it is for.

The status is now read before the outcome is acted on, in one place that
every federated method goes through. `NewUser` is exempt because it
cannot name an account that already exists; the other outcomes all
resolve to a user id, which is what makes the check possible this early.

Same shape as the passkey sign-count bug from #13/#14 — a write that
happens before the check that should have refused the request — and far
lower impact, which is why it was filed rather than rushed.

Two tests, both verified to fail with the fix removed:

- a repeat sign-in on a disabled account leaves `last_login_at` alone;
- a verified-address match onto a disabled account inserts no identity.

The first of those passed for the wrong reason on its first attempt: I
advanced the test clock an hour to make the timestamp visibly different,
which expired the fake's ID token, so the callback failed at
verification and never reached the linking rules at all. It now advances
a minute, and the comment says why.

329 workspace tests, clippy clean, rustfmt clean, wasm32 clean, cargo
deny passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V8K9TBtmnf29dV6uEP5oM3
@ParallelEntrepreneur
ParallelEntrepreneur merged commit 7f4cd4b into main Sep 7, 2026
7 checks passed
@ParallelEntrepreneur
ParallelEntrepreneur deleted the fix/disabled-account-writes branch September 7, 2026 10:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A disabled account still accrues identity rows and events before issue() refuses it

1 participant