feat(server): informed consent for agent user_claimed flow#1081
Conversation
Two informed-consent additions for the agent email-claim flow: - GET /oauth/device/info?user_code=... (auth-gated) returns the requesting client name + scopes for a pending device code, so the consent page can show WHO is asking and WHAT they get instead of approving a blind code. - The magic-link email reframes as an authorization request (subject + body) when its callbackURL targets the device consent page — so a user doesn't grant third-party access thinking they're completing a routine sign-in. Normal login emails are unchanged. The consent gate itself is already explicit (no auto-approve in the current build, confirmed e2e on prod). Tests cover the info endpoint (authed/401/400) alongside the existing discovery + full-loop suite.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds device consent support: magic-link emails gain an authorization mode and subject, auth flow detects device callbacks to choose that mode, a new authenticated ChangesDevice OAuth Authorization Consent Flow
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
bug_free 88, simplicity 86, slop 0, bugs 0, 0 blockers Read diff/logs: typecheck, unit, and integration all exit 0; integration includes /oauth/device/info coverage. Skipped extra server boot; inspected Better Auth magic-link URL construction instead. Working tree has a dirty packages/owletto submodule pointer outside the HEAD diff. Full verdict JSON{
"bug_free_confidence": 88,
"bugs": 0,
"slop": 0,
"simplicity": 86,
"blockers": [],
"change_type": "feat",
"behavior_change_risk": "low",
"tests_adequate": true,
"suggested_fixes": [],
"notes": "Read diff/logs: typecheck, unit, and integration all exit 0; integration includes /oauth/device/info coverage. Skipped extra server boot; inspected Better Auth magic-link URL construction instead. Working tree has a dirty packages/owletto submodule pointer outside the HEAD diff.",
"categories": {
"src": 68,
"tests": 44,
"docs": 0,
"config": 0,
"deps": 0,
"migrations": 0,
"ci": 0,
"generated": 0
}
}Local review gate — branch protection can require the |
What
Closes the informed-consent gaps on the agent
user_claimedflow (the severe auto-approve was already fixed by the deployed consent-copy build; confirmed e2e on prod — magic-link arrival leaves the tokenauthorization_pendinguntil an explicit Approve).GET /oauth/device/info?user_code=…(auth-gated): resolves a pending device code to its requesting client name + scopes, so the consent page can show who is asking and what they get.callbackURLtargets the device consent page — so a user doesn't grant third-party access thinking they're completing a routine sign-in. Normal login emails are unchanged (defaultmode: 'sign-in').Paired owletto change (lobu-ai/owletto#230): the consent page fetches
/oauth/device/infoand renders "Acme Agent is requesting access — Access: mcp:read, mcp:write."Why
pi flagged that approving a blind code, with a "Sign in to Lobu" email, is a phishing-shaped consent for a flow whose real intent is "authorize an agent to act as you." This makes the email and the consent screen say what's actually happening, so approval is informed.
Test evidence
agent-claim-discovery.test.tsnow 7/7 green vs real PG17+pgvector under Node 22 — adds: info endpoint returns client_name + scopes (authed), 401 unauthenticated, 400 unknown user_code — alongside the existing discovery + full user_claimed loop.Notes
No scope clamp — once consent is explicit and informed, the user grants the full requested scope (read+write), which is correct. Deferred: per-email rate limit + token provenance (hardening), and the auto-approve root-cause was the old SPA's conditional auto-submit, removed in the deployed build.
Summary by CodeRabbit
New Features
Tests
Chores