fix(auth): claim device codes atomically - #654
Merged
IvGolovach merged 1 commit intoJun 4, 2026
Merged
Conversation
Validation * Validation tier: Tier 3 - auth-route runtime change, because the update touches device-code authorization semantics. * TDD red: bun run test __tests__/api/deviceAuthorize.test.ts: FAIL before implementation, update predicate was deviceCodes.id only instead of userCode/expiresAt/userId guards. * bun run test __tests__/api/deviceAuthorize.test.ts: PASS, 2 tests. * bun run test __tests__/api/deviceAuthorize.test.ts __tests__/api/devicePoll.test.ts: PASS, 7 tests. * bun run lint src/app/api/auth/device/authorize/route.ts __tests__/api/deviceAuthorize.test.ts: PASS. * git diff --check: PASS. * git diff --cached --check: PASS. * Ledger: not applicable - not required for selected validation tier/change family. * Version: not applicable - no CLI package or release manifest changed. * Not run: full frontend test suite - not required for selected validation tier; targeted authorize and poll route tests cover the changed auth path. Rollback * git revert HEAD
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why
The previous authorize flow checked device-code eligibility before the update, then updated by row id. Concurrent requests could both observe an eligible code and race to claim it, which risks binding one device code to the wrong user or overwriting an existing claim. The route now lets the database perform the eligibility check and claim together, so only one request can win.
Diff scope
packages/frontend/src/app/api/auth/device/authorize/route.ts: replaces the select-before-update flow with a single guardedUPDATE ... WHERE user_code AND expires_at > now AND user_id IS NULL RETURNING id.packages/frontend/__tests__/api/deviceAuthorize.test.ts: adds route coverage for the atomic claim behavior and the stale/invalid-code rejection path.Branch integrity
main.a86e688d620939d2c973c6d5625baa815ea223d7.0 behind / 1 aheadagainstorigin/main.a86e688d620939d2c973c6d5625baa815ea223d7.origin/mainis an ancestor of this branch.Commit integrity
8df5fe3af173d91d2e946318608c6fc6e191996c fix(auth): claim device codes atomically.Diff hygiene
git diff --name-status origin/main...HEAD: only the device authorize route and its focused API test changed.git diff --check origin/main...HEAD: PASS, no output.Validation mode and proof
Mode 3 - auth-route runtime change, because this changes device-code authorization semantics and relies on database predicate correctness for race safety.
bun run test __tests__/api/deviceAuthorize.test.tsfailed before the implementation because the update predicate only targeteddeviceCodes.idinstead of guardinguserCode,expiresAt, anduserId.bun run test __tests__/api/deviceAuthorize.test.ts __tests__/api/devicePoll.test.ts: PASS, 2 files and 7 tests.bun run lint src/app/api/auth/device/authorize/route.ts __tests__/api/deviceAuthorize.test.ts: PASS, no output.git diff --check origin/main...HEAD: PASS, no output.Required remote gates
Pending - GitHub Actions, Vercel, and mergeability checks will run after the PR is opened.
Migration notes
Not applicable - no database migration changed.
Runtime safety
The route keeps the same request/response contract and error status while moving the eligibility check into the database write. It does not change polling behavior, token issuance, session lookup, expiry duration, or device-code generation. No invariant regression introduced.
Documentation integrity
Not applicable - no docs, commands, or runbooks changed.
Rollback plan
Rollback: revert this PR. DB downgrade: not applicable. Data repair: not applicable. Operational caveats: reverting would restore the select-before-update race in device-code authorization.
Known residual risks
Remote CI and GitHub mergeability are pending until the PR is opened. This relies on the existing database update semantics and does not add schema-level uniqueness or locking because the guarded single-row update is sufficient for the current device-code table contract.
Summary by cubic
Make device-code authorization atomic to remove race conditions. The
POST /api/auth/device/authorizeroute now claims codes in a single guarded update and returns clear errors for invalid, expired, or already-claimed codes.UPDATE ... WHERE user_code AND expires_at > now AND user_id IS NULL RETURNING id.Written for commit 8df5fe3. Summary will update on new commits.