Build with Functor
Use a passkey wallet as admin
createPasskeyWallet, grantSession, execute, revokeSession.How it works
You hold the admin key inside your device's secure hardware, backed by Face ID or Touch ID. The agent holds a separate, scoped session key with a spend cap, an expiry, and a contract allowlist. You can revoke it in one transaction.
The two roles never share a key:
| Role | Key type | Held by | Can be revoked? |
|---|---|---|---|
| Admin (you) | Passkey (P-256) | Your device | No: it's yours |
| Agent | Session (secp256k1) | Agent process | Yes: one tx |
Try it live
Run the complete flow right here — no setup, no code. Each button calls the Functor SDK against BNB testnet. Your passkey stays on your device.
Set up your passkey wallet (you are the admin)
Your passkey secures the wallet.
Create a new one, or sign in with an existing passkey wallet.
Grant a scoped session to the agent
The agent gets a separate key, not yours.
It can only act within the permissions you set here: one hour expiry, 0.001 BNB daily spend cap, only calls back to the same wallet. Your passkey signs the grant.
The agent executes — no passkey involved
The agent uses its own session key to sign this transaction. Your passkey is not touched. The onchain validator checks the session's permissions before the call goes through.
Revoke the session — one transaction
You, the admin, pull the agent's key from Keystore. The effect is immediate and global. The agent's next call will revert at validation. No off-chain coordination required.
Build this in your own app
The steps below are for developers integrating this flow into a browser app (React, Next.js, plain HTML). createPasskeyWallet uses WebAuthn and must run in a browser — it cannot run in Node.js or a terminal.
Step 1: Create the passkey wallet
import { createClient, BNB_TESTNET } from "@functornetwork/agentic-wallet";
const client = createClient({ chains: [BNB_TESTNET] });
const wallet = await client.createPasskeyWallet({
name: "MyApp",
rpId: "myapp.example", // your app's domain
});One biometric prompt. No seed phrase. wallet.signer works with every client method.
Step 2: Grant a session to the agent
You (admin) authorize the agent's key onchain. The agent key is separate from your passkey.
const session = await client.grantSession({
wallet,
signer: wallet.signer, // your passkey signs this
permissions: {
calls: [{ to: "0xSomeContract..." }],
spend: [{ limit: 50_000_000_000_000_000n, period: "day" }], // 0.05 BNB/day cap
},
expiry: Math.floor(Date.now() / 1000) + 24 * 60 * 60, // 1 day
});Step 3: The agent executes, no passkey involved
The agent uses its session key. Your passkey is not touched. The onchain validator enforces the permissions before the call goes through.
// This runs in the agent's process — it has the `session` object.
const result = await client.execute({
session,
calls: [{ to: "0xSomeContract...", data: "0x...", value: 0n }],
});An oversized call, a call to an unauthorized contract, or a call after expiry all revert at validation. The agent literally cannot exceed the leash.
Step 4: Recover your wallet on any device
Recovery matches your passkey's private key (held on your device, synced via iCloud or Google) against the public key registered onchain in the Keystore. Switch devices, come back months later — both halves are still there.
const wallet = await client.recoverFromPasskey({ rpId: "myapp.example" });
// OS shows the passkey picker → biometric → done.Step 5: Revoke the agent
One transaction. Effect is global and immediate.
await client.revokeSession({ wallet, signer: wallet.signer, session });
// The agent's next call reverts at validation.What's next
- Use Case 2: point the agent session at a real DEX with a spend cap.
- Use Case 4: verify any agent's authority with a single free onchain read.