Passkeys
Gardeners should never need a seed phrase to plant trees. Passkey authentication signs people in with the platform authenticator they already have (Face ID, a fingerprint, a device PIN) and backs their identity with a smart account, so field workers get real on-chain records without wallet onboarding. Wallets remain available for stewards and power users; passkeys are the default path.

How it flows
A gardener signs with their device, and Green Goods sponsors the gas, so there's no wallet to set up.
Where it lives in the code
| Layer | Source |
|---|---|
| Passkey server selection | packages/shared/src/config/passkeyServer.ts |
| Auth hooks and providers | packages/shared/src/hooks/auth |
| Runtime wiring and the dev bypass | packages/client/src/routes/WalletRuntimeProviders.tsx |
Authentication branches through the shared auth APIs everywhere; no surface implements its own sign-in. One behavior worth knowing: signing in is not the same as joining a garden, and the two recover independently.
Which sites a passkey works on
A browser offers a passkey only for the domain it was created under. Whoever issues the sign-up options chooses that domain, so the passkey server decides where an account can sign in.
- The Green Goods passkey directory (the agent route
/public/passkeys/rpc) issues every passkey undergreengoods.app, so one account signs in on every Green Goods site. Deployed builds use it by default at the existingVITE_API_BASE_URL, and the agent always serves it. The agent reuses its Pimlico API key to check names registered on the hosted server. - The hosted passkey server issues each site its own hostname, so an account made there signs in only on the site that created it. Accounts made before the directory stay on it and sign in the same way as before.
Sign-in asks the directory first and falls back to the hosted server for a name the directory does not hold. The directory refuses a name the hosted server already holds, which keeps one owner per name across both.
The sites the directory answers are the agent's allowed origins (AGENT_ALLOWED_ORIGINS; the
production list that bun run dev:smoke -- prod expects lives in scripts/dev/smoke-prod.js).
Every directory RPC and its preflight require an explicitly listed origin, and the public API's
automatic Vercel-preview exception does not apply here, so adding a subdomain does not approve it.
Of the listed origins, only https pages under greengoods.app are issued a passkey. The app's
own check that a page sits under the passkey domain (classifyPasskeyCeremonyContext) is a first
filter, not the list.
Working with it locally
You rarely need a real passkey ceremony in development. The dev-only bypass from
Getting Started
(?mockAuth=steward&presentation=pwa) signs you in as a test identity. The Playwright passkey
project (tests/specs/client.passkey.spec.ts) drives a virtual authenticator and expects its
strict server substitute to reject the credential, leaving the user signed out after reload.
The reporting-account passkey specs exercise recovery against local substitutes and stop before
signing. tests/specs/client.session-navigation.ci.spec.ts checks mock-auth sessions and navigation;
it does not prove a wallet or passkey ceremony. Real-device biometrics, remote passkey services,
account creation on a chain and sponsored transactions still need authenticated device QA.
Local development keeps passkeys local-only unless VITE_PASSKEY_SERVER_ENABLED=true enables the
local agent directory. VITE_PASSKEY_RP_ID is a local-development override; deployed sites,
including beta.greengoods.app and beta.admin.greengoods.app, use greengoods.app.
Canonical upstream docs
- passkeys.dev for the practical, platform-by-platform guidance.
- The WebAuthn specification when you need the exact ceremony semantics.
- Pimlico docs for the bundler and paymaster that sponsor a passkey account's transactions.
Next steps
- Getting Started lets you try the app with mock auth.
- Anatomy of a Work Submission follows a gardener from sign-in to a recorded submission.
- Testing Guide lists the Playwright projects that exercise sign-in.