Core Concepts
Quorum authorization connects product users to network-verifiable credentials.
The Wallet backend decides which application users can begin a flow; MPC Nodes
decide whether the submitted credentials authorize the key action.
Components and responsibilities
| Component | Responsibility |
|---|---|
| Client or Approver | Uses an EOA, passkey, or JWT credential to authenticate one exact request without revealing the client's secret |
| Wallet backend | Freezes the request, collects signatures, and groups them as default, approvals, and grantees |
| MPC Nodes | The initiator node receives and broadcasts the request; every participating node verifies the signatures against its keyshare, grants, and policy before independently authorizing the action |
| Policy engine | Uses the authenticated initiator, exact approvers, transaction, and policy to select matching rules, evaluate conditions, and count approvals |
The Wallet backend owns application-specific user and role management. MPC Nodes do not receive or interpret those roles. They authorize requests using
verified credential identities, key-bound grants, and policy rules.
Approval groups and member identities
An approval quorum defines which credentials approve an action and how many approvals are required.
Member identity
An approval member is an exact pair:
(authentication method, credential ID)
| Method | Credential ID |
|---|---|
| EOA | Recovered 20-byte account address |
| Passkey | Verified WebAuthn credential ID |
| JWT | Derived string ID for the verified issuer and subject |
EOA, passkey, and JWT credentials can be approval members. Ephemeral session keys may initiate an allowed signing request, but they cannot be approval members and never contribute a quorum vote.
The configured voting unit is one credential, not one person. A Wallet backend
that requires distinct members must ensure that configured credentials belong
to distinct administrators.
Quorum Approval
The Policy structure defines separate approval quorums for signing and policy management:
{
"version": "1.0",
"epoch": 4,
"management_approval": {
"members": [
{ "method": "eoa", "id": "0x111..." },
{ "method": "passkey", "id": "passkey-a" },
{ "method": "jwt", "id": "derived-jwt-id" }
],
"threshold": 2
},
"rules": [
{
"issuer": [{ "type": "UserId", "id": "key-user" }],
"approval": {
"members": [
{ "method": "eoa", "id": "0x222..." },
{ "method": "passkey", "id": "signer-a" }
],
"threshold": 2
},
"action": "allow",
"chain_type": "ethereum",
"conditions": [
{
"transaction_type": "eip191",
"transaction_attr": "message",
"operator": "eq",
"value": "Approve payroll"
}
]
}
]
}
issuerdefines the initiator of the signing request, which required to be matched for the rule evaluation.Rule.approvalnames the quorum of the Transaction Approvers, and the threshold. For example, the quorum is[Alice, Bob, Charlie]with threshold 2, meaning only 2 signatures from any of the quorum members is required.management_approvalnames the Quorum of Policy Admins, allowed to do policy update and deletion.thresholdis the number of distinct quorum members whose valid signatures must accompany the request. It must be at least2and cannot exceed the number of members.
Key-bound approval capabilities
MPC Nodes bind policy members to the key through credential grants. They
maintain one grant per credential and key:
CredentialGrant
|- key_id
|- identity: method + credential_id
|- capabilities
| Capability | Meaning |
|---|---|
approve_signing | The credential is eligible to approve signing requests governed by a matching Rule.approval |
approve_policy_management | The credential is eligible to approve policy updates and deletions governed by management_approval |
authorization_root | The credential authenticated DKG and remains the policy-management initiator |
Approval capabilities are eligibility to vote. They do not independently allow a credential to initiate signing or modify policy.
MPC Nodes derive approval capabilities from Policy membership:
| Policy location | Derived capability |
|---|---|
management_approval.members | approve_policy_management |
Any rules[].approval.members | approve_signing |
A credential appearing in both locations receives both capabilities. The authorization root is created once during DKG and is not derived from policy.
Authentication roles
Every request carries the signatures of the members taking part, each one in a
named field. The field name is what tells MPC Nodes what that signer is doing.
Which fields a request may carry depends on where it sits in the life of a quorum:
| Stage | Request | What its signatures do |
|---|---|---|
| Set it up | DKG | Fix who the first members are, using the policy carried in the same request |
| Change it | updatePolicy, deletePolicy | Let the current members approve a new policy, and let anyone gaining capability accept it |
| Use it | Signing | Let the members named by a matching rule approve one transaction |
A quorum can only approve once it exists, so the three shapes below are not
interchangeable. MPC Nodes reject a field that does not belong to the request
being made.
In a keygen request
DKG is where a quorum begins. The policy travels inside the DKG request itself, so there is nothing stored on the key yet and no one to approve against. The signatures establish who the members are.
One DKG request can create a key for several signing algorithms at once, and each key is authenticated on its own, so every field is labelled with the algorithm it belongs to:
| Field | Who signs | Counts as an approval? |
|---|---|---|
<sign-alg> | The initiator who creates this key | No. There is no quorum yet. This credential becomes the key's authorization root |
<sign-alg>/grantees[] | Every credential the key's initial policy names, except the root | No. It only proves that the credential's holder agrees to the grant |
const userSignatures = {
secp256k1: secpRootSignature,
'secp256k1/grantees': [adminASignature, adminBSignature],
ed25519: edRootSignature,
};
There is no approvals field here. A new key has no approvers yet.
In a Policy administrative request
Administrative requests can change the quorums that already exists. The policy stored on the key authorizes its own replacement: the current members approve the change, and who the change gives new capability.
| Field | Who signs | Counts as an approval? |
|---|---|---|
default | The initiator who starts the request | Yes, only if their credential is also a member of the quorum for this action |
approvals[] | Everyone approving the request | Yes, once for each signer who is a member of the quorum for this action |
grantees[] | A credential that this request is adding to the policy, or giving more permission to | No. It only proves that the credential's holder agrees to the change |
const userSignatures = {
default: initiatorSignature,
approvals: [adminASignature, adminBSignature],
grantees: [newMemberSignature],
};
The default signature is always required to authenticate the request. It can be counted as an approval if the signer is also a member of the quorum for this action.
An admin's signature can appear in both approvals and grantees in the same
update. For example, an admin who approves an update that also adds him to a rule's
signing quorum. Then, his signature proves the approval of the update with the
authority he already holds, and separately proves his consent to the new signing
capability.
In sign request
The quorum defined in Policy's rules authorizes the right members to approve the transaction to be signed.
| Field | Who signs | Counts as an approval? |
|---|---|---|
default | The initiator who starts the request. Their credential must match a rule's issuer for that rule to apply | Yes, only if their credential is also a member of that rule's approval |
approvals[] | Everyone approving this transaction | Yes, once for each signer who is a member of the matching rule's approval |
grantees[] | Nobody. Signing hands out no new capability, so MPC Nodes reject any entry here | Not applicable |
const userSignatures = {
default: initiatorSignature,
approvals: [signerASignature, signerBSignature],
grantees: [],
};
An ephemeral session key can start a signing request, but it cannot be an approval member.
Authorization lifecycle per key
Policy changes update the approval groups and their key-bound grants together.
This produces two authorization states for a key:
| Event | Grant and policy result |
|---|---|
| DKG without policy | Root grant only; authorization epoch 0 |
| DKG with policy | Root plus policy-derived grants; epoch 1 |
| Policy update | Add, change, or remove policy-derived grants atomically; advance epoch once |
| Policy delete | Remove the policy and every policy-derived grant; retain root; advance epoch once |
| Recreate policy without approval groups | Root authenticates alone; no approval grants are created |
The epoch belongs to the key: each Policy update
must commit the next epoch and Policy deletion carries the current epoch as the
expectedAuthorizationEpoch field of
DeletePolicyRequest,
preventing a stale mutation from applying to newer authorization state.
Continue to Authorization Process for independent signature collection and MPC Node evaluation.