Tokens & permissions
The rule of thumb is simple: give every tool its own key, and make each key open only the doors that tool needs. This page shows you how, with ready-made recipes.
The rule of thumb is simple: give every tool its own key, and make each key open only the doors that tool needs. This page shows you how, with ready-made recipes.
How access works, in four lines#
- Everything that talks to your wallet does it with a token — a secret string, at least 32 characters.
- Each token belongs to an identity: you, a teammate, a bot.
- Each token carries permissions — read the balance, draft a transaction, approve one, and so on.
- Permissions say what you may try. Whether it actually happens still runs the gauntlet of your approval rules. A token that can "approve" still cannot make a transaction go on its own; the two-human rule is still there.
Want to know what a given token can do? Ask it:
canonicalwallet --token-file <path> meWhat you started with#
- operator.token — full access, a human identity. This is your admin key. Use it to hand out other tokens; do not wire it into every little script.
- mcp.token — read-only, an agent identity. Safe to give an AI tool.
Recipes: pick the smallest key for the job#
| The job | Give it | So it can / can't |
|---|---|---|
| Health check | view_status | Just check the wallet is up. |
| Read-only agent | view_status, view_accounts, view_proposal, view_events, decode_calldata (+ manifest) | See everything, change nothing. This is mcp.token. |
| Draft transactions | the read-only set + create_proposal | Propose; never approve or send. |
| Review bot | view_proposal, view_events, decode_calldata | Read and analyze; touch nothing. |
| Approver (a person) | view_proposal, approve_proposal, reject_proposal | Say yes or no; not create or send. |
| Sender | view_proposal, execute_proposal | Send already-approved transactions. |
| Auditor | view_audit, view_events | Read the history for compliance. |
An approver usually needs to be a person (human_operator), because the default rule wants at least one human signature.
Handing out, rotating, and revoking keys#
Handing out a token is something your admin key can just do. Pass the new key in through a file so it never lands in your shell history:
openssl rand -hex 24 > ~/.canonical/review-bot.token
chmod 600 ~/.canonical/review-bot.token
canonicalwallet --token-file ~/.canonical/operator.token client register \
--label review-bot \
--principal-kind service_account \
--client-token-file ~/.canonical/review-bot.token \
--capability view_proposal --capability view_events --capability decode_calldata \
--jsonThen manage them over time:
canonicalwallet client list # who has a key
canonicalwallet client rotate-token --id <registration-id> # swap the secret, same identity
canonicalwallet client revoke --id <registration-id> # cut off accessA few things worth knowing:
- One key per tool. Rotating or revoking one never disturbs the others.
- Rotating a key does not change who they are. Their approvals and their place in the history stay attached to the same identity.
- Add --expires-at to make a key that dies on its own after a date.
When you need finer control than permissions#
Sometimes "can draft transactions" is still too broad, and you want to pin a tool to specific accounts or specific kinds of transaction. That is what per-origin permissions are for:
canonicalwallet permissions list
canonicalwallet permissions grant ...
canonicalwallet permissions revoke ...Putting key-handout itself behind approval#
By default you can register and revoke keys directly. If your rules govern it, the direct command will say so (governance_required) and you go through a proposal instead — which then takes the same two-human approval as any other sensitive change. See Multisig & policy.