Passkey Manager Program
The Passkey Manager Program is the core authorization program for passkey-backed flows on Thru.
From a developer perspective, the key idea is that the passkey does not sign the outer Thru transaction directly. Instead, the program verifies a WebAuthn signature over a challenge built from the wallet nonce, the ordered account list, and the trailing instruction bytes that the program action is authorizing.
Use This When
Section titled “Use This When”- you need passkey-backed authorization for a transfer, CPI flow, or other nonce-bound program action
- you need to reason about authority records, credential lookup accounts, or nonce advancement
- you are integrating WebAuthn or native passkey signatures into a Thru transaction flow
Quickstart
Section titled “Quickstart”Fetch the ABI, generate TypeScript builders, then build instruction bytes and send the outer transaction.
thru abi account get --include-data --out ./passkey-manager.abi.yaml <ABI_ACCOUNT_ADDRESS>
thru abi codegen \ --files ./passkey-manager.abi.yaml \ --language typescript \ --output ./generatedimport { decodeAddress } from "@thru/sdk/helpers";import type { Thru } from "@thru/sdk/client";import { PasskeyInstruction, TransferArgs,} from "./generated/thru/program/passkey_manager/types";
const instructionData = PasskeyInstruction.builder() .payload() .select("transfer") .writePayload( TransferArgs.builder() .set_wallet_account_idx(2) .set_to_account_idx(3) .set_amount(1_000_000) ) .finish() .build();
const tx = await thru.transactions.build({ feePayer: { publicKey: decodeAddress(feePayerAddress) }, program: "taUDdQyFxvM5i0HFRkEK3W45kWLyblAHSnMg4zplgUnz6Z", accounts: { readWrite: [walletAddress, destinationAddress], readOnly: [], }, instructionData,});
const signedWire = await signTransaction(tx.toWireForSigning());const signature = await thru.transactions.send(signedWire);How It Works
Section titled “How It Works”Most passkey-managed flows follow this pattern:
- fetch the nonce from the on-chain wallet account
- build the trailing instruction payload you want the program to authorize
- hash
nonce || ordered account addresses || trailing instruction bytes - sign that challenge with WebAuthn
- encode
validate - concatenate
validatewith the trailing instruction payload - submit the resulting transaction against the Passkey Manager Program
This validate-then-execute model works whether the caller is a first-party wallet, a custom web app, or a mobile/backend integration.
Account Model
Section titled “Account Model”| Account | What it stores | Notes |
|---|---|---|
WalletAccount | Wallet header with num_auth and nonce | In practice, wallet data also includes trailing 65-byte authority records after the fixed header. |
CredentialLookup | Wallet pubkey for a registered credential | Useful when a passkey needs a lookup account for registration or recovery flows. |
Authority Records
Section titled “Authority Records”Wallet authority entries are 65-byte tagged records:
tag = 1: passkey authority, stored as P-256x[32] + y[32]tag = 2: pubkey authority, stored aspubkey[32] + padding[32]
Required Accounts
Section titled “Required Accounts”Passkey-manager instructions rely on stable account indices:
- the fee payer is index
0 - the Passkey Manager Program is index
1 - the wallet account must appear as a non-fee-payer account in the transaction
- trailing instructions reference accounts by their position in the final ordered account list
If you are using the Web SDK, buildAccountContext(...) handles this ordering and index lookup.
Events
Section titled “Events”| Event | What it means |
|---|---|
wallet_created | A new passkey-managed wallet account was created. |
wallet_validated | A validate step succeeded and advanced the wallet nonce. |
wallet_transfer | The wallet transferred balance to another account. |
credential_registered | A credential lookup account was registered for the wallet. |
Instructions
Section titled “Instructions”| Instruction | Use it when | Notes |
|---|---|---|
create | Create a new passkey-managed wallet | Includes the initial authority and a state proof for the new wallet account. |
validate | Submit a WebAuthn proof for the trailing wallet action | Carries r, s, authenticatorData, and clientDataJSON. |
transfer | Move native balance from the managed wallet | Usually follows validate in the same transaction payload. |
invoke | Have the managed wallet call another program | This is the main path for wallet-controlled CPI flows. |
add_authority | Add another passkey or pubkey authority | Useful for multi-authority or recovery flows. |
remove_authority | Remove an existing authority by index | Use with care because authority ordering matters. |
register_credential | Create a credential lookup account | Used when you want a stable on-chain mapping for a credential. |
Integration Surfaces
Section titled “Integration Surfaces”The program stands on its own, but most developers will interact with it through one of these integration patterns:
- Use
@thru/programs/passkey-managerwhen your app needs to buildvalidate,transfer,invoke, or authority-management instructions directly. - Use
@thru/passkeywhen you need the browser WebAuthn registration and signing layer that feeds signatures into passkey-manager transactions. - Embedded-wallet integrations typically use the wallet or provider layer for the outer transaction while relying on passkey-manager for the inner authorization payload.
Mobile
Section titled “Mobile”- Mobile apps can use native passkey surfaces to register a credential and produce the WebAuthn proof locally.
- A common mobile pattern is challenge-submit: fetch or construct the passkey-manager challenge, sign it on-device, then send the signature components and WebAuthn payload back to a backend or transaction service that assembles the final transaction.
Related References
Section titled “Related References”On-Chain Link
Section titled “On-Chain Link”- Program explorer: scan.thru.org/address/taUDdQyFxvM5i0HFRkEK3W45kWLyblAHSnMg4zplgUnz6Z