Passkey Session Key
Create a passkey-backed session key for an ECDSA smart account
Passkey session keys let you authorize temporary access using WebAuthn credentials instead of an ECDSA private key. This is useful when you want users to approve scoped permissions with a device prompt (Face ID/Touch ID) instead of managing another key. The primary account remains ECDSA, while the session key is passkey-based.
If you need multichain support with a single approval, prefer ECDSA smart accounts with ECDSA session keys. That combination supports multi-chain signing via a single signature and is the recommended path for production use.
Import
import { createAccountClient } from "@namera-ai/sdk/account";
import { toWebAuthnKey, WebAuthnMode } from "@namera-ai/sdk/passkey";
import { createSessionKey, createSessionKeyClient } from "@namera-ai/sdk/session-key";Usage
To create a passkey session key for an ECDSA smart account, you:
- Create your ECDSA smart account client.
- Register or login a passkey to get a WebAuthn key.
- Create a passkey session key with policies.
- Build a session key client from the serialized account.
import { createAccountClient } from "@namera-ai/sdk/account";
import { toWebAuthnKey, WebAuthnMode } from "@namera-ai/sdk/passkey";
import { createSessionKey, createSessionKeyClient } from "@namera-ai/sdk/session-key";
import { http } from "viem";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { publicClient } from "./clients";
const signer = privateKeyToAccount(generatePrivateKey());
const accountClient = await createAccountClient({
type: "ecdsa",
signer,
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
chain: mainnet,
client: publicClient,
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
});
const webAuthnSessionKey = await toWebAuthnKey({
mode: WebAuthnMode.Register, // or WebAuthnMode.Login
passkeyName: "passkey name",
passkeyServerHeaders: {},
passkeyServerUrl: "YOUR_PASSKEY_SERVER_URL",
});
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [
// Policies for this session key
],
signer,
webAuthnSessionKey,
});
const serializedAccount = sessionKey.serializedAccounts[0]
?.serializedAccount as string;
const sessionKeyClient = await createSessionKeyClient({
type: "passkey",
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
chain: mainnet,
client: publicClient,
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
serializedAccount,
webAuthnKey: webAuthnSessionKey,
});
// Use sessionKeyClient to send UserOps with the passkey session key.Examples
Create a passkey session key with a paymaster, then build a session key client.
import { createAccountClient } from "@namera-ai/sdk/account";
import { toWebAuthnKey, WebAuthnMode } from "@namera-ai/sdk/passkey";
import {
createSessionKey,
createSessionKeyClient,
} from "@namera-ai/sdk/session-key";
import { createPublicClient, http } from "viem";
import { createPaymasterClient } from "viem/account-abstraction";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
const paymaster = createPaymasterClient({
transport: http("ZERO_DEV_PAYMASTER_URL"),
});
const signer = privateKeyToAccount(generatePrivateKey());
const client = await createAccountClient({
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
chain: mainnet,
client: publicClient,
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
paymaster,
signer,
type: "ecdsa",
});
const webAuthnSessionKey = await toWebAuthnKey({
mode: WebAuthnMode.Register,
passkeyName: "passkey name",
passkeyServerHeaders: {},
passkeyServerUrl: "YOUR_PASSKEY_SERVER_URL",
});
const sessionKey = await createSessionKey({
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [
// Policies for this session key
],
signer,
type: "passkey",
webAuthnSessionKey,
});
const serializedAccount = sessionKey.serializedAccounts[0]
?.serializedAccount as string;
const sessionKeyClient = await createSessionKeyClient({
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
chain: mainnet,
client: publicClient,
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
serializedAccount,
type: "passkey",
webAuthnKey: webAuthnSessionKey,
});
// Use this to get the session key to send transactions.The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using Pimlico's Bundler, Biconomy's Bundler, or another Bundler service.
Multichain note
Passkey session keys do not support multi-chain signing. If you want the same session key across multiple chains, you must approve once per chain (N prompts for N chains). For a single approval across many chains, use an ECDSA session key with an ECDSA smart account.
Policies
Policies define the conditions under which a session key can sign UserOps. See Policies for detailed policy builders and examples.
Parameters
type
- Value:
"passkey"
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
});accountType
- Value:
"ecdsa"
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
});webAuthnSessionKey
- Type:
WebAuthnKey
const webAuthnSessionKey = await toWebAuthnKey({
mode: WebAuthnMode.Register,
passkeyName: "passkey name",
passkeyServerHeaders: {},
passkeyServerUrl: "YOUR_PASSKEY_SERVER_URL",
});
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
});clients
- Type:
Client[]
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
});signer
- Type:
Signer
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
});policies
- Type:
Policy[] - See Policies.
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [/* ... */],
signer,
webAuthnSessionKey,
});entrypointVersion
- Type:
EntrypointVersion=>"0.6" | "0.7" | "0.8" | "0.9"
import { EntryPointVersion } from "viem/account-abstraction";
const = await createSessionKey({
: "passkey",
: "ecdsa",
: [publicClient],
: "0.7",
: "0.3.2",
: [],
,
,
});kernelVersion
- Type:
KernelVersion=>"0.0.2" | "0.2.2" | "0.2.3" | "0.2.4" | "0.3.1" | "0.3.2" | "0.3.3"
Note: Kernel 0.2.x supports only Entrypoint 0.6. For Kernel 0.3.x, you can use Entrypoint 0.7 or 0.8.
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
});index
const sessionKey = await createSessionKey({
type: "passkey",
accountType: "ecdsa",
clients: [publicClient],
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
policies: [],
signer,
webAuthnSessionKey,
index: 0n,
});serializedAccount
- Type:
string
const serializedAccount = sessionKey.serializedAccounts[0]
?.serializedAccount as string;
const sessionKeyClient = await createSessionKeyClient({
type: "passkey",
client: publicClient,
chain: mainnet,
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
serializedAccount,
webAuthnKey: webAuthnSessionKey,
});webAuthnKey
- Type:
WebAuthnKey - Use the same WebAuthn key you created for the session key.
const sessionKeyClient = await createSessionKeyClient({
type: "passkey",
client: publicClient,
chain: mainnet,
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
serializedAccount,
webAuthnKey: webAuthnSessionKey,
});client
- Type:
Client<HttpTransport, Chain, JsonRpcAccount | LocalAccount | undefined>
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});bundlerTransport
- Type:
Transport
const sessionKeyClient = await createSessionKeyClient({
type: "passkey",
client: publicClient,
chain: mainnet,
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
serializedAccount,
webAuthnKey: webAuthnSessionKey,
});chain
- Type:
Chain
import { mainnet } from "viem/chains";paymaster
- Type:
PaymasterClient
import { createPaymasterClient } from "viem/account-abstraction";
import { createSessionKeyClient } from "@namera-ai/sdk/session-key";
const paymaster = createPaymasterClient({
transport: http("ZERO_DEV_PAYMASTER_URL"),
});
const sessionKeyClient = await createSessionKeyClient({
type: "passkey",
client: publicClient,
chain: mainnet,
bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
entrypointVersion: "0.7",
kernelVersion: "0.3.2",
serializedAccount,
webAuthnKey: webAuthnSessionKey,
paymaster: paymasterClient,
});