RPC access: open, owner and admin
How Tenzro nodes authorise calls: closed by default, three access classes, signatures from the paying account, OAuth 2.1 with DPoP and HTTP message signatures.
Tenzro Network is closed by default. Every method a node serves is classified, and a method that is not classified is refused before it runs. Reading public state needs nothing. Anything that moves money or changes state needs a signature from the account that pays for it or owns what changes. Operator policy on a node needs that node's operator.
The network stays permissionless: any developer can call any node's RPC, MCP or A2A surface from anywhere, signing with their own hardware-rooted keys, with no per-node enrolment.
The three classes
| Class | Who can call | Credential | Examples |
|---|---|---|---|
| Open | Anyone | None | Blocks, balances, validators, model lists, DID resolution, verification |
| Owner | The account that pays or owns | A signature, a DID envelope or a DPoP-bound session of that account | Transfers, passkey and recovery changes, payments, escrows, agent actions |
| Admin | The operator of the node you are calling, or an administrator its policy names | A DPoP-bound access token of that DID | Model lifecycle, pricing and schedules, the access policy, rentals, the operator's own stake |
tenzro_listRpcMethods (and tenzro rpc methods in the CLI) returns every method with its class, so a client can tell "I need to sign this" from "only the operator can do this" before it calls. The full grouping is in the API reference.
Open
Open methods read public state or verify something. They need no headers.
curl -s https://rpc.tenzro.com \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tenzro_getFinalizedBlock","params":[]}'Owner: proof from the paying account
An owner method changes something that belongs to an account. The node accepts proof only from that account. An administrator's session is deliberately not accepted for owner methods: a node's host must not be able to move an account's funds, rewrite a developer's tool or change how a payee gets paid.
There are three kinds of proof.
Signed transactions. A transfer or contract call is a transaction signed with the account's composite hybrid signature: a classical signature and an ML-DSA-65 signature over the same canonical hash, non-separable, with the post-quantum key bound to the account. It is submitted with eth_sendRawTransaction; the node verifies both halves before admitting it. A passkey account sends the same native transactions with tenzro_sendRawTransaction, signed by a passkey its keystore links and checked in consensus. See Hardware-rooted keys and Device linking and recovery.
DID envelopes. Actions that belong to an identity rather than a balance (updating a skill you published, terminating an agent swarm you control, publishing a site) carry a DID envelope. The envelope is signed by the identity's key and commits to:
- the DID of the signer,
- the method it authorises,
- a SHA-256 hash of the canonical parameters,
- a timestamp and a random nonce.
Because the method and parameters are inside the signature, an envelope for one call cannot be replayed as another, and each nonce is accepted once. Over JSON-RPC the envelope goes in the did_envelope parameter; over HTTP it goes in the X-Tenzro-DID-Envelope header; A2A and MCP carry it in their message metadata. POST /verify/did-envelope on the Web API checks one for you.
Address signatures. Where a record names its owner by address instead of a DID, the call carries signature and public_key over a domain-separated message that names the method and binds the parameters.
The SDKs build all of these for you from a signer backed by your passkey or device key. The key never leaves your control; the node only ever sees signatures.
Sessions for agents: OAuth 2.1 with DPoP
Agents and services that make many calls use short-lived sessions instead of a signature per request. Onboarding (tenzro_onboardHuman, tenzro_onboardDelegatedAgent, tenzro_onboardAutonomousAgent) issues an OAuth 2.1 access token bound to a DPoP key (RFC 9449), with the agent's permissions expressed as Rich Authorization Requests (RFC 9396).
Every request then carries two headers:
Authorization: DPoP <access token>
DPoP: <proof JWT signed by the holder's key for this method and URL>A stolen token is useless without the key that signs the proofs. A delegated agent is bounded by its controller's delegation scope and spending policy; when it calls something the controller wants to approve, the node answers -32002 with an approval_id, and the call proceeds once the controller approves. Revoking a controller's DID revokes the tokens of every agent under it. Tokens are refreshed, introspected and revoked through /oauth/token, /oauth/introspect and /oauth/revoke.
The MCP server at https://mcp.tenzro.com/mcp uses the same scheme: read tools are open, and write tools need a DPoP-bound bearer token.
HTTP message signatures
Agents calling paid HTTP resources can sign the request itself with HTTP Message Signatures (RFC 9421), in the Signature-Input and Signature headers. Covered components typically include @method, @target-uri, @authority and content-digest, plus any payment headers. The keyid is a DID, optionally with a key fragment (did:tenzro:machine:...#key-1), so any verifier can resolve it.
Every node publishes the public keys needed to verify these signatures:
| Route | Contents |
|---|---|
GET /.well-known/jwks.json | JWK Set of agent signing keys |
GET /.well-known/jwks.json/{keyid} | One key by keyid |
GET /.well-known/http-message-signatures-directory | Signature directory for automated agents |
Payment credentials carried alongside the HTTP signature keep their own hybrid binding, so the payment stays quantum-safe whatever the HTTP-layer algorithm. See x402 and MPP.
Admin: operator only
Admin methods set the policy of one node: which models it serves, at what price and when, who may use it, which rentals are open, and the operator's own stake. The caller must be the node's operator DID or an administrator the node's access policy names, signed in with a DPoP-bound access token (tenzro access sign-in signs with the machine's TPM or Secure Enclave; a person signs in with a passkey). There are no admin tokens or API keys. No admin method can change network-wide state such as the validator set, fees or protocol parameters; those change only through governance.
Node listeners bind to loopback by default, so a fresh node exposes nothing off the machine until the operator chooses to.
Paying without an account
Paid HTTP routes such as /v1/chat/completions need no prior relationship. The route answers 402 Payment Required with its price and accepted methods; the client pays with x402 or MPP, in TNZO or stablecoins, and retries with the payment attached. The payment is signed by the paying account, like any other owner action. See Payments.
Private nodes
Who may use a node at all is its access policy (access.toml, set with tenzro-node access or tenzro access set): open, signed in, named DIDs, agents under Terms, or closed, per surface (RPC, MCP, A2A, Web API) and per method class. It never gates consensus and peer-to-peer traffic, so a closed node still validates and gossips, and it never gates /health and /ready. A model the operator publishes to the network stays callable by anyone who pays, even on a closed node.
Headers at a glance
| Header | Sent by | Purpose |
|---|---|---|
Authorization: DPoP ... and DPoP | Agent or app | OAuth 2.1 session bound to a DPoP key |
X-Tenzro-DID-Envelope | Identity owner | Signed authorisation for one call |
Signature-Input, Signature | Agent | RFC 9421 HTTP message signature |
Several can be present on one request; each gate checks its own header.