accessKey.authorize
Authorizes an access key through a local signing account or a connected wallet. Local accounts submit a transaction; JSON-RPC accounts request a wallet authorization.
Usage
import { Account, Expiry, P256 } from 'viem/tempo'
import { client } from './viem.config'
// 1. Define root account
const account = Account.fromSecp256k1('0x...')
// 2. Define access key attached to the root account
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
// 3. Authorize the access key
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
})
console.log('Transaction hash:', receipt.transactionHash)
Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdefimport { Account, createClient } from 'viem/tempo'
export const client = createClient({
account: Account.fromSecp256k1('0x...'),
})Authorize Through a Wallet
For a JSON-RPC account, authorize calls wallet_authorizeAccessKey. Omit accessKey to let the wallet generate and store the key. The wallet returns a signed authorization and its root address; this request does not require a transaction. authorizeSync remains an onchain action.
import { createClient, custom } from 'viem'
import { tempo } from 'viem/chains'
import { Addresses, Expiry, tempoActions } from 'viem/tempo'
const client = createClient({
account: '0x0000000000000000000000000000000000000001',
chain: tempo,
transport: custom(window.ethereum),
}).extend(tempoActions())
const { keyAuthorization, rootAddress } = await client.accessKey.authorize({
expiry: Expiry.hours(1),
limits: [{ token: Addresses.pathUsd, limit: 1_000_000_000n }],
fundingPolicy: true,
})fundingPolicy: true asks the wallet to resolve its default funding policy. The wallet must support wallet_authorizeAccessKey; unsupported methods and rejected requests propagate without falling back to transaction submission.
With Expiry and Spending Limits
You can set an expiry and per-token spending limits when authorizing an access key:
import { Account, Expiry, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
expiry: Expiry.hours(1),
limits: [
{
token: '0x20c0000000000000000000000000000000000001',
limit: 1000000n,
},
],
})With Periodic Spending Limits
Use the period field on limits to set a recurring spending cap that resets after the given number of seconds:
import { parseUnits } from 'viem'
import { Account, Period, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
limits: [
{
token: '0x20c0000000000000000000000000000000000001',
limit: parseUnits('1000', 6),
period: Period.months(1), // resets every month
},
],
})With Call Scopes
Use scopes to restrict which contracts and functions the access key can call:
import { parseUnits } from 'viem'
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
limits: [
{
token: '0x20c0000000000000000000000000000000000001',
limit: parseUnits('10000', 6),
},
],
scopes: [
{
address: '0x20c0000000000000000000000000000000000001',
selector: 'transfer(address,uint256)', // or "0xa9059cbb"
recipients: ['0xcafebabecafebabecafebabecafebabecafebabe'], // optional
},
],
})import { parseUnits } from 'viem'
import { Account, P256, Scopes } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
limits: [
{
token: '0x20c0000000000000000000000000000000000001',
limit: parseUnits('10000', 6),
},
],
scopes: [
Scopes.tip20('0x20c0000000000000000000000000000000000001')
.transfer({
recipients: ['0xcafebabecafebabecafebabecafebabecafebabe'],
}),
],
})With a Witness
Use witness to bind a 32-byte value into the authorization's signing hash. This lets you bind a single signature to an arbitrary offchain context (e.g. a server-issued challenge), or use it as a revocation handle that can be burned onchain (via accessKey.burnWitness) to invalidate the authorization before it is submitted (TIP-1053):
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
witness: '0x...',
})Admin Keys
Set admin: true to authorize an unrestricted admin key. Admin keys can manage the account's other access keys and cannot carry expiry, limits, or scopes (they are ignored). Requires the T6 hardfork (TIP-1049):
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
admin: true,
})Once authorized, an admin key can authorize (and manage) other keys on behalf of the account. Pass the admin key as the account: viem binds the authorization to the parent account and signs it with the admin key directly.
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
// Admin key (previously authorized with `admin: true`)
const adminKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
// New key to authorize on behalf of the account
const childKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
account: adminKey,
accessKey: childKey,
})Authorize Public Keys
Instead of passing an AccessKeyAccount, you can authorize a key by its public key or address directly:
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
// Authorize by public key
const { receipt } = await client.accessKey.authorizeSync({
accessKey: {
publicKey: '0x...',
type: 'p256',
},
}) You can also authorize by address:
import { Account } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
// Authorize by address
const { receipt } = await client.accessKey.authorizeSync({
accessKey: {
address: '0x...',
type: 'p256',
},
}) Asynchronous Usage
The example above uses a *Sync variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync accessKey.authorize action and wait for inclusion manually:
import { Actions, Account, Expiry, P256 } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
access: account,
})
const { hash } = await client.accessKey.authorize({
accessKey,
expiry: Expiry.hours(1),
})
const receipt = await client.waitForTransactionReceipt({ hash: hash! })
const { args }
= Actions.accessKey.authorize.extractEvent(receipt.logs)Return Type
authorize always returns the same shape:
type ReturnValue = {
rootAddress: Address
keyAuthorization: KeyAuthorization.Signed
hash: Hex | undefined
}Local accounts submit the signed authorization and return its transaction hash. JSON-RPC accounts return the wallet's signed authorization with hash: undefined. Numeric authorization fields are decoded.
authorizeSync returns the onchain event and receipt:
type ReturnType = {
/** The account that authorized the key. */
account: Address
/** The public key that was authorized. */
publicKey: Address
/** The signature type. */
signatureType: number
/** The expiry timestamp. */
expiry: bigint
/** Transaction receipt */
receipt: TransactionReceipt
}Parameters
accessKey
- Type:
{ accessKeyAddress: Address; keyType: string } | { address: Address; type: string } | { publicKey: Hex; type: string }
The access key to authorize. Accepts an AccessKeyAccount, or an object with { address, type } or { publicKey, type }. Optional for JSON-RPC accounts, where omission asks the wallet to generate and store a key.
admin (optional)
- Type:
boolean
Whether to authorize the key as an admin key. Admin keys are unrestricted and can manage the account's other access keys; expiry, limits, and scopes are ignored. Requires the T6 hardfork (TIP-1049).
expiry (optional)
- Type:
number
Unix timestamp when the key expires. Required for JSON-RPC accounts.
fundingPolicy (optional)
- Type:
true | bigint | FundingPolicy.Inline
Use an existing policy ID, an inline { admins, rules } policy, or true to select the funding handler's configured policyId. The default is resolved before signing; explicit IDs and inline policies are unchanged.
The policy's administrators can change its rules for all attached access keys. Relay.funding supplies current registered policyRules when filling payments.
See access key funding for a complete example.
keyType (optional)
- Type:
'secp256k1' | 'p256' | 'webAuthn'
For JSON-RPC accounts, selects the type of wallet-generated key. Defaults to the wallet's preferred type. A supplied accessKey determines its own key type.
limits (optional)
- Type:
{ token: Address; limit: bigint; period?: number }[]
Spending limits per token. Optionally include period (in seconds) to make the limit periodic. It resets after each period. Use Period.months(1), Period.seconds(n), etc. from ox/tempo for convenience.
scopes (optional)
- Type:
{ address: Address; selector?: Hex | string; recipients?: Address[] }[]
Call scopes restricting which contracts/selectors this key can call. Each scope entry specifies a contract address, an optional 4-byte function selector, and optional recipient addresses (for transfer-like functions). If scopes is set to [] (empty array), the key cannot make any calls.
witness (optional)
- Type:
Hex
Optional 32-byte witness bound into the authorization's signing hash. Can be burned onchain via accessKey.burnWitness to invalidate the authorization before it is submitted (TIP-1053).
account (optional)
- Type:
Account | Address
Account that sends the transaction. For a coordinated multisig transaction, pass the multisig account.
feeToken (optional)
- Type:
Address | bigint
Fee token for the transaction.
Can be an unpaused USD-denominated TIP-20 token address or ID. Use client.fee.validateToken({ token }) to validate a token before submitting a transaction or setting it as a fee preference.
feePayer (optional)
- Type:
Account | true
Fee payer for the transaction.
Can be a Viem Account, or true if a Fee Payer Service will be used.
gas (optional)
- Type:
bigint
Gas limit for the transaction.
maxFeePerGas (optional)
- Type:
bigint
Max fee per gas for the transaction.
maxPriorityFeePerGas (optional)
- Type:
bigint
Max priority fee per gas for the transaction.
nonce (optional)
- Type:
number
Nonce for the transaction.
nonceKey (optional)
- Type:
'expiring' | bigint
Nonce key for the transaction. Use 'expiring' to use expiring nonces (TIP-1009), which enables concurrent transaction submission without nonce ordering.
owner (optional)
- Type:
Account | Address
Local owner that signs one coordinated multisig approval.
validBefore (optional)
- Type:
number
Unix timestamp before which the transaction must be included.
validAfter (optional)
- Type:
number
Unix timestamp after which the transaction can be included.
throwOnReceiptRevert (optional)
- Type:
boolean - Default:
true
Whether to throw an error if the transaction receipt indicates a revert. Only applicable to *Sync actions.