WebAuthn
Makechain uses WebAuthn passkeys as a primary authentication method for account ownership, key management, and session re-authentication. Passkeys provide phishing-resistant, biometric-backed credentials that replace seed phrases and browser extension wallets.
Standard vs Makechain WebAuthn
Standard WebAuthn follows a simple challenge-response pattern. The server generates a random challenge, the client signs it with a passkey, and the server verifies the P-256 signature. The challenge carries no semantic meaning.
Makechain's custody flow repurposes the WebAuthn challenge. Instead of a random nonce, the challenge is a Makechain-native AccountKeychain digest for a specific account operation such as SIGNER_ADD, SIGNER_REMOVE, KEYCHAIN_AUTHORIZE, or KEYCHAIN_REVOKE.
| Aspect | Standard WebAuthn | Makechain custody |
|---|---|---|
| Challenge | Random server nonce | AccountKeychain digest |
| Purpose | Prove passkey ownership | Authorize key management |
| Verification | Server-side P-256 check | Consensus P-256 verification against embedded public key |
| Wire format | Standard CBOR attestation | Custom envelope (0x02 + WebAuthn data + signature + public key) |
| State change | None | Adds or removes a signing key |
Both flows use the same passkey credential and the same P-256 curve. The difference is what the passkey signs and who verifies it.
Passkey ownership
EVM wallets on Tempo support WebAuthn passkeys natively. Tempo validates P-256 signatures at the chain level via the 0x76 transaction type, so no onchain secp256r1 verifier contract is needed.
When you use a passkey wallet in Makechain:
- Your passkey's P-256 public key maps to an EVM address
- This address is the canonical Makechain
owner_address - Custody signatures use native AccountKeychain digests signed by this passkey
owner_address is the sole canonical account identity in Makechain. There is no KEY_ADD, onchain account allocation, ownership transfer, or recovery flow in the protocol.
Custody signatures
Custody signatures authorize key management without an onchain transaction. The account owner signs a native AccountKeychain digest with their passkey, and validators verify the signature during consensus.
AccountKeychain digests
Custody digests are deterministic binary payloads encoded with commonware-codec and hashed with Keccak-256. The operation byte is part of the signed payload:
0x01 KEYCHAIN_AUTHORIZE
0x02 KEYCHAIN_REVOKE
0x03 SIGNER_ADD
0x04 SIGNER_REMOVE
0x05 SIGNER_REQUEST
The digest also carries the target key family (custody 0x01 or envelope 0x00), the Makechain network, owner address or request owner address, target key, validity window, nonce when applicable, allowed projects when applicable, and witness bytes for keychain messages.
Wire format
When a custody signature uses WebAuthn P-256, the signature field carries a custom envelope. The AccountKeychain digest is encoded as a base64url string in the clientDataJSON challenge field.
0x02 | authenticatorData || clientDataJSON | signature:64 | pubkey_x:32 | pubkey_y:32
The embedded P-256 public key determines the custody key id. There is no recovery bit.
Verification steps
Validators verify WebAuthn custody signatures by:
- Parsing the envelope to extract
authenticatorData,clientDataJSON, the P-256 signature, and the embedded P-256 public key - Checking authenticator flags — User Present (UP) and User Verified (UV) must both be set
- Validating
clientDataJSON— thetypefield must bewebauthn.getand thechallengefield must match the expected AccountKeychain digest (base64url-encoded) - Computing the signed data —
SHA-256(authenticatorData || SHA-256(clientDataJSON)) - Verifying the P-256 signature against the embedded public key
- Deriving the custody key id from the embedded public key and checking it against the root
owner_addressor an active admin custody key
Clients normalize P-256 signatures to low-S form before encoding. Validators also reject high-S secp256k1 and P-256 signatures so each digest has a single canonical encoding.
Origin and RP ID are not enforced
Makechain treats a WebAuthn assertion as portable custody signature material. Validators do not check the rpIdHash in authenticatorData or the origin in clientDataJSON, and there is no fixed relying-party allowlist. Authority comes entirely from the challenge binding (the challenge must equal the AccountKeychain digest), the webauthn.get type, the UP/UV flags, the P-256 signature, and the embedded public key. A passkey created against any RP ID or origin can therefore authorize custody operations as long as it controls the derived custody key id. The wire envelope itself is the externally-fixed ox/tempo SignatureEnvelope WebAuthn variant.
Session authentication
Session authentication uses standard WebAuthn ceremonies for fast re-authentication. Unlike custody signing, the challenge is a random server nonce with no EIP-712 semantics and no protocol state change.
This flow is useful when you return to the docs site, playground, or workbench and need to prove you still control your passkey without reconnecting a full wallet session. The webauthx library (from wevm) handles server-client ceremony orchestration.
import { Authentication } from "webauthx/server";
import { Authentication as ClientAuth } from "webauthx/client";
// Server: generate challenge
const options = Authentication.getOptions({
rpId: "makechain.net",
allowCredentials: [{ id: credentialId }],
});
// Client: sign with passkey
const response = await ClientAuth.sign(options);
// Server: verify signature
const result = Authentication.verify(response, {
publicKey: storedPublicKey,
challenge: options.challenge,
rpId: "makechain.net",
origin: "https://docs.makechain.net",
});
Session authentication and custody signing share the same passkey credential. The distinction is in what gets signed and where verification happens:
| Aspect | Session authentication | Custody signing |
|---|---|---|
| Challenge | Random nonce | AccountKeychain digest |
| Verifier | Application server | Consensus validators |
| State change | None (session only) | SIGNER_ADD or SIGNER_REMOVE |
| Library | webauthx | Custom envelope encoder |
Try it
Register a passkey credential and authenticate with it, then compare the standard WebAuthn flow to Makechain's custody signing model.
Verification claims
External address verification also supports WebAuthn P-256 passkeys. When you link an Ethereum address to your Makechain account via VERIFICATION_ADD, the claim signature can be a WebAuthn envelope.
The EIP-712 type for verification claims is:
- VerificationClaim —
VerificationClaim(address owner, address ethAddress, uint256 chainId, uint32 verificationType, string network)
For VERIFICATION_ADD, clients put the WebAuthn envelope directly in claim_signature. The signature bytes are self-describing, so there is no separate claim_key_type field. Standard ECDSA claims use a 65-byte signature.
This means a passkey that controls an owner_address can also prove ownership of its associated Ethereum address without a separate wallet extension or private key export.
:::tip[Try it]
The register an account guide walks through using a passkey wallet with address-native Makechain, including a live SIGNER_ADD where your passkey signs the AccountKeychain custody authorization and the message is submitted to testnet.
:::