<!-- tempo-docs-context -->
> Source: [/docs/development/account-keychain](https://tempo.xyz/developers/docs/development/account-keychain.md)
> Section: [Tempo EVM](https://tempo.xyz/developers/docs/development.md). Build on Tempo EVM: wallets and keys, payments, transactions and fees, TIP-20 Tokens, contracts, exchange, network details, nodes, protocol specifications, and changelog.
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

# Account Keychain

The Account Keychain holds each account's access keys and checks every transaction they sign against the limits you set.

Access keys are extra keys that sign for an account, and they are live on mainnet and testnet. A limited access key works within its spending limits, expiry, and scopes. An [admin access key](https://tempo.xyz/developers/docs/development/account-keychain#admin-access-keys) has none of these bounds. The Account Keychain is a precompile, a contract built into Tempo, at `0xAAAAAAAA00000000000000000000000000000000`. To build with access keys, start with the [Access keys](https://tempo.xyz/developers/docs/accounts/access-keys) guide.

Both [account types](https://tempo.xyz/developers/docs/accounts/keys) use access keys. A [single-key account](https://tempo.xyz/developers/docs/development/single-key-accounts) is controlled by one root key, the key its address derives from. A [configurable account](https://tempo.xyz/developers/docs/development/configurable-accounts) is controlled by owner keys, whose weights must reach a threshold to approve. Configurable accounts run only on the [Tempo Accounts devnet](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet), a separate test network, until [T14](https://tempo.xyz/developers/docs/protocol/upgrades/t14), the planned upgrade that brings them to testnet and mainnet.

An account authorizes an access key, which then signs within its spending limits, expiry, and scopes.

## Access key types

Each access key has a signature type, the `signatureType` value you pass when you authorize it. The Account Keychain identifies each of an account's keys by its key ID, an address.

| Key type | `signatureType` | Key ID |
| --- | --- | --- |
| secp256k1 | `0` | The key's address |
| P-256 | `1` | The key's address |
| WebAuthn | `2` | The address derived from the passkey's public key |
| Configurable account | `3` | The account's address. Its owners sign for it. Devnet until T14 ([TIP-1111](https://tips.sh/1111)). |

## Access key restrictions

| Restriction | Rule |
| --- | --- |
| Spending limits | One per [TIP-20 token](https://tempo.xyz/developers/docs/protocol/tip20/overview), Tempo's stablecoin standard, in base units. Each limit's `period` of `0` sets a one-time limit; a positive `period` resets it every `period` seconds. |
| What limits count | Direct TIP-20 transfers, approval increases, fees the account pays, and and tokens that protocol precompiles pull, such as a Stablecoin DEX swap's input. A `transferFrom` that spends an allowance the account already granted doesn't count, and neither do non-TIP-20 assets. |
| Expiry | A Unix timestamp. The key stops working at that second. Omit it for no expiry; a direct [`authorizeKey`](https://tempo.xyz/developers/docs/development/account-keychain#authorize-an-access-key) call passes `type(uint64).max` instead. |
| Scopes | Any call, or an allowlist of `(target, selector, recipients)`: the contracts, functions, and payees the key can use. An empty allowlist denies every call; a target with no selector rules allows any function. Only the calls the key signs directly are checked, not calls those contracts make in turn. |
| Contract creation | A key can't deploy a contract directly, but it can call a permitted factory that does. |
| Key management | Limited keys can't authorize, change, or revoke keys, including themselves. Admin access keys can. |

Tempo rejects an expired key with [`KeyExpired`](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#error-keyexpired), a transaction over a limit with [`SpendingLimitExceeded`](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#error-spendinglimitexceeded), and a call outside the scopes with [`CallNotAllowed`](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain#error-callnotallowed).

## Access keys on each account type

| | [Single-key account](https://tempo.xyz/developers/docs/development/single-key-accounts) | [Configurable account](https://tempo.xyz/developers/docs/development/configurable-accounts) |
| --- | --- | --- |
| Authorizes, changes, and revokes keys | The root key | Owners whose weights reach the threshold, with a `0x05` [multisig signature](https://tempo.xyz/developers/docs/development/configurable-accounts#multisig-signature-format) |
| Acts as another account's access key | As type `0`, `1`, or `2`, matching its root key | As type `3`, signed by its owners |

Any account can also be another account's access key, as the second row shows. [Admin access keys](https://tempo.xyz/developers/docs/development/account-keychain#admin-access-keys) can also manage keys on either type. Access keys never count toward a threshold.

<span id="authorizing-an-access-key" />

## Authorize an access key

An account authorizes a key in one of two ways: a `key_authorization` field on a [Tempo Transaction](https://tempo.xyz/developers/docs/protocol/transactions/spec-tempo-transaction), or a direct call to the precompile.

| Path | Behavior |
| --- | --- |
| `key_authorization` on a transaction | The account signs the authorization, and the new key can sign the transaction that carries it. The key stays authorized even if the calls revert. |
| `authorizeKey` call | The account calls the precompile. The authorization rolls back if the transaction reverts. |

Viem's `client.accessKey.signAuthorization` and `authorize` both use the `key_authorization` path. An optional `witness`, an application-defined `bytes32`, binds the authorization to an offchain challenge, such as a sign-in nonce. To cancel an authorization that hasn't landed yet, the account burns its witness with `client.accessKey.burnWitness`. Tempo then rejects any authorization signed with that witness.

## `0x04` keychain signature

An access key signs a transaction with a `0x04` keychain signature. Viem builds this signature for any access-key account, such as `Account.fromP256(privateKey, { access: account })`. To build it yourself:

```text
signature    = 0x04 || account || access_key_signature
inner_digest = keccak256(0x04 || tx_signature_hash || account)
```

The access key signs `inner_digest`; a configurable account acting as an access key signs it with its owners, as a `0x05` multisig signature. `tx_signature_hash` is the transaction's signing hash ([keychain signature format](https://tempo.xyz/developers/docs/protocol/transactions/spec-tempo-transaction#keychain-variable-length)). Tempo checks that the key is authorized for `account`, unexpired, unrevoked, and of the stored type, then enforces its limits and scopes. Since the T1C network upgrade, Tempo rejects the legacy `0x03` keychain format.

<span id="revoke-access" />

## Revoke an access key

`revokeKey(keyId)` is permanent: that key ID can never be authorized again for the account. Configuration updates (owner changes), [account upgrades](https://tempo.xyz/developers/docs/development/single-key-accounts#upgrade-to-a-configurable-account), and revoking an admin key leave every other key in place, so revoke each key separately.

<span id="admin-access-keys" />

## Admin access keys

An admin access key ([TIP-1049](https://tips.sh/1049), live since the [T6 upgrade](https://tempo.xyz/developers/docs/protocol/upgrades/t6#admin-access-keys)) has no limits, expiry, or scopes. It can authorize and revoke keys, including admin keys, and change a limited key's limits and scopes, but it can't change a configurable account's owners. Its holder can spend the whole balance, so store it as carefully as a root or owner key.

## Account Keychain functions

| Function | Purpose | Viem action |
| --- | --- | --- |
| `authorizeKey` | Authorize a limited key | `client.accessKey.authorize` |
| `authorizeAdminKey` | Authorize an admin key | `client.accessKey.authorize` with `admin: true` |
| `revokeKey` | Revoke a key | `client.accessKey.revoke` |
| `updateSpendingLimit` | Set one token's limit; resets the remaining amount to the new limit and keeps the period | `client.accessKey.updateLimit` |
| `setAllowedCalls`, `removeAllowedCalls` | Replace or remove a target's scope | `writeContract` |
| `getKey` | Read a key's type, expiry, and status | `client.accessKey.getMetadata` |
| `getRemainingLimitWithPeriod` | Read the remaining limit and period end | `client.accessKey.getRemainingLimit` |
| `getAllowedCalls` | Read a key's scopes | `readContract` |
| `isAdminKey` | Check whether a key is the root key or an active admin key | `client.accessKey.isAdmin` |
| `getTransactionKey` | Read the key signing the current transaction; `address(0)` means the root key | None; call it from a contract |

For `writeContract` and `readContract`, pass `Abis.accountKeychain` and `Addresses.accountKeychain` from `viem/tempo`. Functions that change keys must be called directly by the account's transaction (`msg.sender == tx.origin`). The [specification](https://tempo.xyz/developers/docs/protocol/transactions/AccountKeychain) lists every function, event, and error.
