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 an EIP-712 typed data hash. This lets a passkey authorize specific protocol operations like SIGNER_ADD and SIGNER_REMOVE in a single gesture.
| Aspect | Standard WebAuthn | Makechain custody |
|---|---|---|
| Challenge | Random server nonce | EIP-712 signing hash |
| Purpose | Prove passkey ownership | Authorize key management |
| Verification | Server-side P-256 check | Onchain + consensus P-256 recovery |
| Wire format | Standard CBOR attestation | Custom envelope (authData + clientJSON + sig + v) |
| 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 V2:
- Your passkey's P-256 public key maps to an EVM address
- This address is the canonical Makechain
owner_address - All custody signatures (
SIGNER_ADD,SIGNER_REMOVE) use EIP-712 typed data signed by this passkey
owner_address is the sole canonical account identity in V2. 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 an EIP-712 typed data hash with their passkey, and validators verify the signature during consensus.
EIP-712 domain and types
The domain is shared across all custody and verification signatures:
{
"name": "Makechain",
"version": "1",
"chainId": "host_chain_id(network)"
}Three typed payloads cover the live custody and app-attribution operations:
- SignerAdd —
SignerAdd(address owner, bytes32 key, uint32 scope, uint64 validAfter, uint64 validBefore, uint64 nonce, bytes32[] allowedProjects, uint32 network) - SignerRemove —
SignerRemove(address owner, bytes32 key, uint64 validAfter, uint64 validBefore, uint64 nonce, uint32 network) - SignerRequest —
SignerRequest(address requestOwner, bytes32 key, uint64 validAfter, uint64 validBefore, uint32 network)
Wire format
When custody_key_type=2 (WebAuthn P-256), the custody signature field carries a custom envelope instead of a raw 65-byte ECDSA signature. The EIP-712 hash is encoded as a base64url string in the clientDataJSON challenge field.
┌──────────────────────────────────────────────────┐
│ authDataLen │ authenticatorData │
│ (2 bytes LE) │ (37+ bytes) │
├──────────────┼────────────────────────────────────┤
│ jsonLen │ clientDataJSON │
│ (2 bytes LE) │ (variable) │
├──────────────┴────────────────────────────────────┤
│ signature (64 bytes) │ recovery bit (1 byte) │
└──────────────────────────────────────────────────┘
The minimum envelope size is 107 bytes. Signatures longer than 65 bytes trigger the WebAuthn verification path.
Verification steps
Validators verify WebAuthn custody signatures by:
- Parsing the envelope to extract
authenticatorData,clientDataJSON, the P-256 signature, and the recovery bit - 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 EIP-712 hash (base64url-encoded) - Computing the signed data —
SHA-256(authenticatorData || SHA-256(clientDataJSON)) - Recovering the P-256 public key from the signature and signed data
- Deriving the EVM address from the recovered public key and comparing against the expected
owner_address
The P-256 signature uses low-S normalization to ensure deterministic recovery.
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) provides clean 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 | EIP-712 hash |
| 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 must set claim_key_type = 2 when the claim signature is a WebAuthn envelope. That envelope uses the same wire format and validation steps as custody signatures. Standard ECDSA claims use the default key type and 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.