braid
GH-42 · Add OAuth login
ARArjun Rao

Add OAuth login

GH-42
surfaced · 3 threads woven
◆ braid claim GH-423 threads dispatched from here, disjoint scopes
thread_afailed
Backendsrc/auth/
Intent — replay-safe token exchange under concurrent logins
agent_start · Claude Code
edit + go test ×9
2 attempts rejected
verify failed · 12/14
thread_bpassed
Frontendweb/login/
Intent — sign-in page that starts OAuth + handles callback
agent_start · Codex
build login page
kept: rendered sign-in
verify passed · e2e
thread_cpassed
Teststest/oauth/
Intent — cover valid / expired / replayed / malformed codes
agent_start · Claude Code
table-driven tests
kept: exchange + errors
verify passed · 14/14
Promote → octopus-merge b + c
thread_a woven in as evidence (not merged) · sign · decision record

Add OAuth login

GH-42
4 agents3 threads636k tokens$7.03 cost18m wall-clock

Timeline shows agent wall-clock by thread; the right column keeps tokens and cost visible.

Claude Code Codex verify dropped approach
thread / agents
0 3m 6m 9m 12m 15m 18m
tokens · cost
thread_afailed
Backend src/auth/
2 agentsCCCC
Claude Code · refresh-token rotation
Claude Code · single-token reuse
347k $4.57
142k + 205k
thread_bpassed
Frontend web/login/
1 agentCx
Codex · login page · redirect flow
168k $1.34
1 agent
thread_cpassed
Tests test/oauth/
1 agentCC
Claude Code · table-driven tests
121k $1.12
1 agent
Converged at 16m
octopus-merge b + c · $7.03 total · thread_a retained as evidence

Add OAuth login

GH-42
✓ Ready to promote
Gates clear · 2 passed · 1 evidence thread · 0 scope violations.

Work intent

local draft
Set out to do
Ship OAuth redirect/callback and prove token exchange stays replay-safe.
Agents did
Ran backend, frontend, and test threads; kept the failed backend attempt as evidence.
Why
Popup auth and optimistic token reuse failed; redirect flow and table tests survived.
Needs human
Promote this braid; GH-49 carries the replay-safe storage follow-up.
What next
Seal the decision record, then continue token storage as a separate braid.

Threads

Thread evidence from signed events: Intent · Attempt · Decision · Verification.

Backend · token exchange
src/auth/CClaude Code · Arjun
verify failed
IntentIntent
Server-side token exchange must stay replay-safe across simultaneous device logins.
ApproachesAttempt ×2
rejectedIn-memory refresh-token rotation

Concurrent-login race; failed test.

rejectedOptimistic single-token reuse

Replay succeeded; failed assertion.

No approach held; kept as evidence. Follow-up: GH-49.
VerdictVerification
verify failed · 12 / 14 tests
Frontend · login page
web/login/xCodex · Arjun
verify passed
IntentIntentDeclaration
Add a sign-in page that kicks off the OAuth flow and handles the provider callback.
ApproachesAttempt ×2 · Decision
rejectedPopup-window flow

The auth popup is blocked by default in Safari and loses state on mobile browsers. Dropped.

chosenFull-page redirect + callback route

Works across every browser with no popup permission, carrying state in the OAuth state param. Chosen for cross-browser reliability over the popup's smoother feel.

VerdictVerification
verify passed · e2e green
Tests · integration
test/oauth/CClaude Code · Arjun
verify passed
IntentIntentDeclaration
Cover the token-exchange endpoint across valid, expired, replayed and malformed codes.
ApproachesAttempt ×2 · Decision
rejectedOne test function per case

Five near-identical functions duplicated the exchange setup — harder to extend as cases grow.

chosenTable-driven cases

Single setup, one row per code state — trivial to add cases. Chosen to keep the suite maintainable as OAuth grows.

VerdictVerification
verify passed · 14 / 14 · coverage 91%

Add OAuth login

GH-42

The diff, traced back to the braid. Every hunk shows which thread wrote it and whether that thread's verdict held — so you read what changed and why it survived in one place.

src/auth/token.goevidence · not mergedthread_a — 2 attempts rejected, verify failed
- func Exchange(code string) (*Token, error) {- t := refreshInMemory(code) // race under concurrent logins- return t, nil- }
web/login/LoginPage.tsxmergedthread_b — kept, e2e passed
+ export function LoginPage() {+ return <SignInButton onSuccess={handleCallback} />+ }
test/oauth/exchange_test.gomergedthread_c — 14/14
+ func TestExchange_ReplaySafe(t *testing.T) {+ // table-driven: valid, expired, replayed, malformed+ }

Developer dashboard

Judgment queue · 1 intervention · 1 ready to promote · 1 running spend check.

main · braidkit/Prototype

Judgment queue

$11.83 open spend · 3 decisions
!
Replay-safe token store GH-49needs human
reconfirm goalstale 1dfollow-up from GH-42 thread_a · no scopes dispatched
Add OAuth login GH-42ready
all gates clear3 threads terminal · 2 passed · 1 evidence thread · $7.03
caching GH-51running
open spend $4.80thread_b running · thread_c queued · no event for 48s

Scratch

Unsigned local work waiting to attach into a braid.

3 sessions · explicit attach
local · unsigned

Scratch to attach

3
CSV export work
src/reports · web/reports · test/reports — grouped by repo and adjacent work.
3 selectedchoose target braid before signing · no auto-attach

All braids

Full braid inventory across active, surfaced, promoted, and dropped lifecycle states. Scratch lives separately until attached.

4 braids · 1 ready
main · braidkit/Prototype
sorted by last activity
Issue
Lifecycle
Threads
Gate
Activity
caching GH-51
src/cache · invalidation thread running, tests queued
active
3 threads
1 passed · 1 running · 1 queued
blockedterminal boundary open
48s ago
382k · $4.80 open spend
Add OAuth login GH-42
web/login · callback flow · failed backend evidence retained
surfaced
3 threads
2 passed · 1 evidence
readyall promote gates clear
18m ago
636k · $7.03
Replay-safe token store GH-49
follow-up discovered from GH-42 thread_a
active
0 threads
dispatch not started
reconfirmgoal pending
1d ago
4 events · $0.00
rate limits GH-38
src/ratelimit · middleware · tests merged with decision record
3 threads
3 passed · merged
sealedrecord verified
3d ago
376k · $3.81