Skip to content

How to use a Passport Protocol signer with permissionless.js

Passport is an MPC-based programmable, distributed, and non-custodial key management system, that allows users to generate wallets, scoped to their application, either via user Passkeys or any developer defined authentication method. Our signer allows you to sign messages and transactions with a Passport Network account.


To use Passport with permissionless.js, you'll first need to make sure you have configured a scope for your application. For this you can follow the guides below:

  • Refer to the Passport documentation for instructions on setting up your application with Passport.
  • For a primer on setting up your scope you can check here.


Integrating permissionless.js with Passport is straightforward after setting up the project. Passport provides an Externally Owned Account (EOA) wallet to use as a signer with permissionless.js accounts.

Create the Passport signer

After following the Passport documentation, you will have access to a Passport WalletClient object that you can use to create a SmartAccountSigner object, both examples show how to register a user but if you already have a registered user you can skip the registration step. For Developer Owned Auth, the authentication is handled on the developer's side. For more detail on both you can check the authentication guide.

Passkey Signer
import { Passport, TESTNET_RSA_PUBLIC_KEY } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { createPassportClient } from "@0xpass/passport-viem";=
import { walletClientToSmartAccountSigner } from "permissionless";
import { http } from "viem";
import { sepolia } from "viem/chains";
const passport = new Passport({
  scope_id: "scope_id",
  signer: new WebauthnSigner({
    rpId: "rpId",
    rpName: "rpName",
  enclave_public_key: TESTNET_RSA_PUBLIC_KEY,
const fallbackProvider = http("");
await passport.setupEncryption();
await passport.register({
  username: "test",
  userDisplayName: "test",
const [authenticatedHeader] = await passport.authenticate({
  username: "test",
  userDisplayName: "test",
const client = await createPassportClient(
const signer = walletClientToSmartAccountSigner(client);

Use with permissionless.js

import { signerToSimpleSmartAccount } from "permissionless/accounts"
import { createPublicClient, http } from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { sepolia } from "viem/chains"
export const publicClient = createPublicClient({
	transport: http(""),
	chain: sepolia,
const smartAccount = await signerToSimpleSmartAccount(publicClient, {
	signer: smartAccountSigner,
	factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454",