Skip to content

fix(auth): Quick Connect poll capability + unlinked KOSync registration#118

Merged
bndct-devops merged 1 commit into
mainfrom
fix/auth-hardening
Jul 5, 2026
Merged

fix(auth): Quick Connect poll capability + unlinked KOSync registration#118
bndct-devops merged 1 commit into
mainfrom
fix/auth-hardening

Conversation

@bndct-devops

Copy link
Copy Markdown
Owner

Two fixes from the 2026-07-03 auth-surface review.

Fixes

  • Quick Connect codes can no longer be brute-forced into a login. Polling a code required nothing but the code itself — six characters, guessable within the 5-minute window, returning a full login JWT once authorized. /initiate now also issues a long random poll_token, and polling (now POST /poll) requires the code + token pair; a guessed code gets the same 410 as an unknown one. The short code is still all you type on the already-signed-in device. Startup migration adds the column; pre-existing rows expire unpollable within their TTL.
  • A KOReader sync registration can no longer claim your account. The unauthenticated KOSync registration endpoint (POST /v1/users/create, KOReader's "Register" button) attached the new credential to whatever Tome account shared the username — so anyone knowing a username could register it first and have their reading land on that account. Registrations now start unlinked; linking is the authenticated Settings path, which also reclaims a squatted name by overwriting its key.

Tests

  • tests/test_auth_hardening.py — 9 new tests (poll-token required / indistinguishable-from-unknown, legacy tokenless rows unpollable, KOSync create stays unlinked, Settings relink reclaims).
  • Full backend suite green (814 passed); npm run build typechecks clean (LoginPage poll change).

Verification

Emulator + endpoint checks performed on a branch-code instance (see the release-prep session notes).

Two fixes from the 2026-07-03 auth surface review:

- Quick Connect: /initiate now issues a long random poll_token alongside
  the 6-character code, and polling (now POST /poll) requires the pair.
  Guessing a code returns the same 410 as an unknown one — the ~30-bit
  display code can no longer be brute-forced into a login JWT during the
  authorization window. Startup migration adds the column; pre-existing
  rows expire unpollable within their 5-minute TTL.
- KOSync /v1/users/create (unauthenticated, KOReader's register button)
  no longer auto-links the new sync credential to a same-named Tome
  account. Registrations start unlinked; the authenticated Settings path
  (POST /api/auth/me/kosync) links — and reclaims a squatted username by
  overwriting its key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bndct-devops
bndct-devops merged commit d435b56 into main Jul 5, 2026
2 checks passed
@bndct-devops
bndct-devops deleted the fix/auth-hardening branch July 5, 2026 09:46
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