Skip to content

feat: add dormant walletless auth and signed wallet linking#110

Merged
dirtybits merged 22 commits into
mainfrom
feat/walletless-base-card-access
Jul 18, 2026
Merged

feat: add dormant walletless auth and signed wallet linking#110
dirtybits merged 22 commits into
mainfrom
feat/walletless-base-card-access

Conversation

@dirtybits

@dirtybits dirtybits commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a provider-neutral Clerk buyer-session boundary behind separate server and public preview flags
  • map stable Clerk subjects to opaque AgentVouch buyer-account UUIDs without treating email or wallets as primary identity
  • add fail-closed sign-in, session, logout, navbar, account, and Clerk middleware wiring while preserving existing wallet paths
  • add signed Solana and Base Sepolia wallet linking with five-minute server challenges bound to account, session, origin, CAIP-2 chain, normalized address, purpose, nonce, and expiry
  • require same-origin mutation checks plus Clerk strict reverification before challenge issuance and verification
  • consume challenges atomically, reject replay, and prevent an already-linked chain-qualified address from being taken by another buyer account
  • add a guarded additive migration for buyer accounts, identities, wallet links, one-time wallet-link challenges, and marketplace access grants
  • fix first-login resolution so a newly inserted account is returned through PostgreSQL data-modifying-CTE output instead of an invisible same-statement base-table join

Verification

  • npm run format:check
  • npm run lint --workspace @agentvouch/web
  • npm run typecheck --workspace @agentvouch/web
  • npm test --workspace @agentvouch/web -- --run — 117 files, 747 tests passed
  • npm run verify:chain-map — 25 Solana instructions, 22 Base state-changing functions, 26 mapped rows
  • npm exec --workspace @agentvouch/web -- next build --webpack
  • adversarial coverage includes wrong purpose/message, wrong account/chain/nonce, expired challenge, unsupported version, invalid signature, replay, cross-origin requests, missing auth, missing strict reverification, Base-mainnet rejection, and cross-account address takeover
  • exact pre-wallet-link fix head 7eaf5c41b3c85d087352ce1912e688e4a71b9a07 deployed as dpl_8cbfNeptUmWyXsGZ4J5fNn2DEfqK and reached READY
  • fresh synthetic Clerk session returned authenticated on its first request with an opaque account UUID; same-origin logout returned revoked; runtime monitoring showed only 200s and no error/fatal logs

Clerk preview

  • installed the Vercel Marketplace Clerk development instance and configured Google plus passwordless email verification codes
  • disabled password, phone, username, and passkey sign-in
  • scoped buyer-auth flags and the isolated DATABASE_URL only to preview branch feat/walletless-base-card-access
  • deleted both synthetic Clerk users after the original session smoke
  • fixed the development-preview host_invalid handshake by removing Clerk's production-only Frontend API proxy; regression coverage prevents it from being re-enabled
  • exact signed head 7a7e044ad028d2e0c08fbd3993aa89e11a6b3289 deployed as dpl_6XPJgkptyEv859YtR2fXQi8qHHDw and reached READY
  • browser smoke reached the Google account chooser and completed passwordless email-code sign-in with Clerk's reserved +clerk_test address and fixed OTP; the synthetic user was deleted afterward
  • live Solana/Base wallet-signature UI smoke remains pending because no test wallet was connected during this auth correction

Database rehearsal and preview isolation

  • verified the intended project as Vercel-managed agentvouch-postgres (calm-meadow-36819154), not the legacy Neon project
  • completed the original four-table migration rehearsal on disposable branch br-billowing-pine-af5amekf, including idempotency and catalog checks, then deleted it
  • created expiring preview branch br-empty-hat-afcrsu56, reran the guarded migration/preflight, and used it for the authenticated session smoke
  • applied and catalog-verified only the additive buyer_wallet_link_challenges table plus active-challenge index on br-empty-hat-afcrsu56
  • did not query, migrate, or change the primary production database

Rollout state

  • production has no buyer-auth feature flags and remains fail-closed
  • https://agentvouch-walletless-preview.vercel.app remains the isolated preview alias
  • the preview Neon branch expires on 2026-07-20; retain it only while PR preview verification continues
  • Base card checkout and Base mainnet remain disabled; this PR does not enable eip155:8453

Note

High Risk
Touches authentication, Stripe fulfillment/revocation, and paid download authorization across Solana and Base Sepolia; regressions could grant or deny access incorrectly despite feature flags and preserved legacy wallet paths.

Overview
Introduces walletless commerce for buyers who sign in with Google or email (Clerk), pay by card, and download paid skills without connecting a wallet. The durable identity is an opaque buyer account UUID linked to Clerk; email and Stripe customer ids are never treated as wallet addresses.

Authentication and lifecycle: @clerk/nextjs sits behind AGENTVOUCH_BUYER_AUTH_* flags with a provider-neutral buyerSession boundary, same-origin logout, and a user.deleted webhook that soft-deletes accounts and strips identity links while retaining grant audit rows. Clerk middleware runs without the production-only Frontend API proxy so preview handshakes work.

Stripe (separate card-access flags): Checkout can bind metadata to an authenticated account (stripe-account-access) instead of a signed wallet. Webhooks upsert marketplace_access_grants only—no usdc_purchase_receipts or Base/Solana protocol receipts—and refunds/disputes revoke those grants idempotently. Legacy wallet-bound Stripe checkout and entitlements are unchanged.

Downloads: Raw access resolution accepts an active account grant (including Base Sepolia listings) as an off-chain path alongside wallet entitlements and x402; unsupported legacy Base contracts now return a structured 402 migration hint instead of 500.

Wallet linking: Optional Solana / Base Sepolia addresses are proven via server challenges (account, session, origin, nonce) with strict Clerk reverification; challenges are consumed atomically and cannot steal an address already linked to another account.

Data and UI: Guarded additive migration for buyer accounts, identities, wallet links, challenges, and grants; account page, sign-in route, navbar auth, and skill-page Pay by Card / account download flows with session retry after Clerk handshake races.

Docs (STRIPE_*, CHAIN_CAPABILITY_MAP) and extensive tests cover auth, Stripe, raw access, and migration invariants. Base mainnet remains blocked.

Reviewed by Cursor Bugbot for commit 4b19cb9. Bugbot is set up for automated code reviews on this repo. Configure here.

@dirtybits

Copy link
Copy Markdown
Owner Author

Clerk preview verification is complete for the buyer-session foundation.

  • Vercel Marketplace Clerk development instance provisioned; Google and email-code auth enabled; password/phone/username/passkeys disabled.
  • Auth flags and isolated DATABASE_URL are scoped only to feat/walletless-base-card-access; production buyer-auth flags remain absent.
  • The initial synthetic first-login smoke exposed a PostgreSQL data-modifying-CTE visibility bug. Fix 7eaf5c4 carries account status through CTE output; the full local gate passed (format, lint, typecheck, 732 Vitest tests, chain-map verification, webpack build).
  • Exact fix deployment dpl_8cbfNeptUmWyXsGZ4J5fNn2DEfqK reached READY.
  • A fresh synthetic Clerk session succeeded on its first request with one opaque active buyer account and one Clerk identity link; same-origin logout returned revoked=true.
  • Runtime monitoring for that deployment showed two 200 requests and no error/fatal logs.
  • Both synthetic Clerk users were deleted. No production DB preflight/migration ran, and Base mainnet remains blocked.

Remaining live-auth evidence is the interactive Google redirect and email-code component flow; automated browser navigation rejected the new preview hostname before page load, so that is not claimed as verified.

@dirtybits dirtybits changed the title feat: add dormant walletless buyer auth foundation feat: add dormant walletless auth and signed wallet linking Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Final pre-review verification for 4b5db2511818a9e5fd4986f9acfa93f289e086f1:

  • GitHub Actions run 29623169849: test and contracts jobs passed.
  • Exact-head Vercel deployment: https://agentvouch-ps57czbqb-dirtybitsofficials-projects.vercel.app
  • Stable hardened-preview alias: https://agentvouch-walletless-preview.vercel.app
  • Live anonymous boundary smoke on the stable alias:
    • GET /api/auth/buyer/session → 200 (configured: true, enabled: true, authenticated: false)
    • GET /sign-in → 200
    • GET /account → 200
    • GET /api/account/wallet-links → 401
    • same-origin anonymous POST /api/account/wallet-links/challenge → 401
    • cross-origin POST /api/account/wallet-links/challenge → 403
  • Exact deployment runtime logs: no error/fatal entries during the smoke window.
  • Isolated Neon preview branch migration verified; primary database untouched.
  • Production auth/card flags and Base mainnet remain disabled.

Interactive Google/email login and a real Solana/Base wallet-signature smoke remain pending because the embedded browser blocks the new Vercel preview host at the client layer (net::ERR_BLOCKED_BY_CLIENT) before the app loads.

@dirtybits
dirtybits marked this pull request as ready for review July 18, 2026 00:34
@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ef1eddaa-e459-43d9-87d2-9f6bf5a99c32)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3f166db4-9fe6-444d-a8c1-ee84d6ae83d1)

Copy link
Copy Markdown
Owner Author

Clerk preview correction verified on 7a7e044ad028d2e0c08fbd3993aa89e11a6b3289:

  • root cause: Clerk Frontend API proxying is unsupported for development instances
  • fix: removed frontendApiProxy from clerkMiddleware; added a wiring regression test
  • local: format, lint, typecheck, 117 files / 747 tests, and webpack production build passed
  • CI run 29624811456: success
  • Vercel: dpl_6XPJgkptyEv859YtR2fXQi8qHHDw READY; hardened alias updated
  • Google: redirect reached the Google account chooser
  • email: reserved Clerk test address completed the 424242 verification-code flow and reached the authenticated AgentVouch account page
  • cleanup: synthetic Clerk user deleted; primary database and production configuration untouched
  • observability: no error/fatal runtime logs on the exact deployment during the smoke

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_88ef142d-14cc-4312-b849-52fd4c7030a6)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_1eae2e97-99f4-4fab-9d38-a6a3f12b9b01)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_7f2ef11e-b23a-45b3-8bc3-cdccd7013779)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_07d7ca70-2cb3-49eb-b423-732f6d27da24)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3bd70afc-cf2c-4555-84f4-6e519574e8df)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_b69a1931-824f-43d8-bb37-0434ec72c95f)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_b2816701-36b4-40dc-83d3-cadb49d96fc5)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_8d175ac2-1690-4f31-bb37-74227081c0e8)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_8ceced49-f746-465e-b0d1-e36c2a4294d7)

@dirtybits

Copy link
Copy Markdown
Owner Author

Final walletless preview verification on signed head df43b38:

  • Full local gate passed: format, web lint, typecheck, 120 Vitest files / 771 tests, chain-map verification (25 Solana instructions, 22 Base state-changing functions, 26 rows), and next build --webpack.
  • Clerk user.deleted reconciliation is proven on isolated Neon branch br-empty-hat-afcrsu56 through preview deployment dpl_GnzNv64GYVKd9vmi4ksjU2AMyZyo. Disposable user user_3GfFmgGCJPvUR4HPqZ9OXrd3Lmn soft-deleted opaque account 160a89db-9782-4859-999f-d1d0e9bac130; identity links are 0, the audit grant remains 1, and active access is 0. Initial delivery and explicit single-message replay both returned HTTP 200, and the state remained idempotent. The obsolete mismatched-secret endpoint was deleted.
  • Fresh Base Sepolia x402 settlement used dedicated relayer 0xd9C9504B410D6675D9c2eDAb7902839eC726EE6C (not the deployer). Settlement 0x3dc21c2b1ee908a3badc2d8a98a9a8a2ea69bf901de181bba2301a4872c7ff0b succeeded at block 44,292,096 for exactly 1,000,000 USDC micros. Anonymous raw access returned 402; paid access, duplicate retry, and signed re-download returned 200; isolated Neon has exactly one chain-qualified receipt and one entitlement.
  • The stable alias remains https://agentvouch-walletless-preview.vercel.app. Production feature flags/database were not changed, and Base mainnet remains blocked.

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_27b11010-551a-4f35-ad0c-7ba69981261b)

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e3b18b40-56ef-4ad5-90b8-401054f51122)

@dirtybits

Copy link
Copy Markdown
Owner Author

Publication closeout on current head 3601496: test passed in 2m01s, contracts passed in 1m48s, Vercel reports Deployment has completed, and the PR is non-draft, cleanly mergeable, with a clean worktree.

Signing note: implementation commit df43b38 is verified, but evidence-only commits 30f728b and 3601496 are unsigned because the local 1Password SSH signer repeatedly failed. Before merge, re-sign both after 1Password is unlocked; force-pushing the rewritten branch requires explicit approval.

@dirtybits
dirtybits force-pushed the feat/walletless-base-card-access branch from 3601496 to 4b19cb9 Compare July 18, 2026 07:18
@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ac3f7da8-d90a-4e50-b778-a16e1b6829ea)

@dirtybits
dirtybits merged commit be74229 into main Jul 18, 2026
4 checks passed
@dirtybits
dirtybits deleted the feat/walletless-base-card-access branch July 18, 2026 07:24
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