Docs · Guides
Approvals
The human approval ceremony: what the reviewer sees, what the passkey proves, and what Custody signs.
The invariant
The human signs exactly what they see. The review screen is rendered from the challenge response, not from the page the person was looking at — so there is no second copy that could show one amount while the signature commits to another.
The ceremony, step by step
- Policy answers REQUIRE_APPROVAL and an obligation is opened.
- The approver opens it in the Console and presses Review and approve.
- The Console asks the Gateway for a challenge. The Gateway returns the challenge and its own reading of the obligation.
- The Console throws away what it was displaying and renders that reading.
- The passkey prompt appears. The person authenticates — this proves presence.
- The Gateway verifies the assertion, then asks Custody to sign the approval payload with the approver's Ed25519 key.
- The signed approval is recorded. The browser never holds that key and never sees the artifact.
What the passkey is, and is not
A passkey confirms a person was present. It does not sign the approval — that is a separate key held by Custody. Using a passkey as a signing key would put the authority in a browser.
Refusals the ceremony makes
| Code | Meaning |
|---|---|
| self_approval_prohibited | The requester cannot approve their own request. |
| duplicate_approver | One person cannot satisfy a two-person rule twice. |
| approval_binding_mismatch | The signature covers a different obligation. |
| approval_expired | The window closed before it was completed. |
| approval_replayed | That approval has already been consumed. |
| signing_unknown | Custody may or may not have signed. Held for a person; never retried blindly. |
What you can do today
READ ONLY See the approval queue — /projects/:id/approvals
Where: Approvals
Reading the queue and one approval. Deciding is APPROVER.
Requires: ADMIN, APPROVER, AUDITOR
AVAILABLE Approve or reject, with a passkey — /projects/:id/approvals/:id
Where: Approvals → an approval → Review and approve
First: APPROVER, an enrolled passkey, and a provisioned Custody approval key — all three now have a screen.
Requires: APPROVER
AVAILABLE Enrol a passkey — /security/passkeys
Where: Security → Your passkeys → Register a passkey
First: A signed-in session.
AVAILABLE See and disable your passkeys — /security/passkeys
Where: Security → Your passkeys
First: An enrolled passkey.
The ceremony is implemented and tested end to end against a real Gateway, real Custody and the real WebAuthn protocol. Two of its prerequisites — holding APPROVER, and enrolling a passkey — have no screen yet, so completing it today needs those set up out of band.