Use a passkey with MetaMask Smart Accounts
Passkeys eliminate the need for traditional seed phrases that are difficult to remember, enabling a more seamless and secure way for users to access their EOAsExternally owned account (EOA) A private-key-controlled account with no built-in programmable execution logic.. Compared to traditional EOAs which use secp256k1 elliptic curve to generate key pairs and signatures, a passkey-based EOA uses the secp256r1 (P-256) elliptic curve.
MetaMask Smart Accounts is signer-agnostic and natively supports passkeys (P-256 elliptic curve signatures), so you can use a passkey as the signer.
Unlike EOA ECDSA signatures, passkey (WebAuthn) signatures are non-deterministic. Signing the same message twice produces different signatures, because the authenticator includes fresh data such as counter in each assertion.
Prerequisites
Steps
1. Install dependencies
Install the Smart Accounts Kit and other dependencies in your project:
- npm
- Yarn
- pnpm
- Bun
npm install @metamask/smart-accounts-kit ox
yarn add @metamask/smart-accounts-kit ox
pnpm add @metamask/smart-accounts-kit ox
bun add @metamask/smart-accounts-kit ox
2. Create a passkey
To create a passkey signer, use Viem's createWebAuthnCredential function to securely register the passkey (WebAuthn credential).
import { createWebAuthnCredential } from 'viem/account-abstraction'
const credential = await createWebAuthnCredential({
name: 'MetaMask Smart Account',
})
3. Create a smart account
Once the passkey is created, use the Viem WebAuthn Account to configure your passkey as a MetaMask smart accountMetaMask smart account A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations. signer.
The deployParams parameter needs the X and Y coordinates of the P-256 public key. Since WebAuthn credentials store
a compressed public key, you need to deserialize it, and extract the X and Y coordinates.
- example.ts
- config.ts
import { publicClient } from './config.ts'
import { Implementation, toMetaMaskSmartAccount } from '@metamask/smart-accounts-kit'
import { toWebAuthnAccount } from 'viem/account-abstraction'
import { Address, PublicKey } from 'ox'
import { toHex } from 'viem'
const webAuthnAccount = toWebAuthnAccount({ credential })
// Deserialize compressed public key
const publicKey = PublicKey.fromHex(credential.publicKey)
// Convert public key to address
const owner = Address.fromPublicKey(publicKey)
const smartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [owner, [toHex(credential.id)], [publicKey.x], [publicKey.y]],
deploySalt: '0x',
signer: { webAuthnAccount, keyId: toHex(credential.id) },
})
import { http, createPublicClient } from 'viem'
import { sepolia as chain } from 'viem/chains'
const transport = http()
export const publicClient = createPublicClient({
transport,
chain,
})
Next steps
- See how to send a user operation.
- To sponsor gas for end users, see how to send a gasless transaction.