# Authorize Access Keys

## Overview

An access key is a secondary key that an account authorizes to sign transactions on its behalf.
The root key signs a key authorization granting the access key permission, so a user can sign
transactions without a passkey prompt every time while keeping the root key offline. This guide
covers creating and using a key; see [Set Permissions & Limits](/tempo/guides/access-keys/permissions)
to restrict what a key can do.

[See the Access Keys specification](https://docs.tempo.xyz/protocol/transactions/AccountKeychain)

## Recipes

These recipes assume you have [set up a Tempo client](/tempo).

### Authorize an Access Key

Create an access key bound to a root account, then authorize it onchain with
[`accessKey.authorize`](/tempo/actions/accessKey.authorize).

:::code-group
```ts twoslash [example.ts]
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'

// 1. Define the root account.
const account = Account.fromSecp256k1('0x...')

// 2. Create an access key bound to the root account.
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
  access: account,
})

// 3. Authorize the access key.
const { receipt } = await client.accessKey.authorizeSync({
  accessKey,
})
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

### Authorize with Call Scopes

Use `scopes` to restrict an access key to specific contract calls. You can pass raw scope objects
directly, or use [`Scopes`](/tempo/utilities/Scopes) builders for typed selectors.

:::code-group
```ts twoslash [Raw]
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,
  scopes: [
    {
      address: '0x20c0000000000000000000000000000000000001',
      selector: 'transfer(address,uint256)',
      recipients: ['0xcafebabecafebabecafebabecafebabecafebabe'],
    },
  ],
})
```

```ts twoslash [Scopes]
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,
  scopes: [
    Scopes.tip20('0x20c0000000000000000000000000000000000001')
      .transfer({
        recipients: ['0xcafebabecafebabecafebabecafebabecafebabe'],
      }),
  ],
})
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

### Defer Authorization to a Transaction

Sign the authorization offline with [`accessKey.signAuthorization`](/tempo/actions/accessKey.signAuthorization),
then attach it to the next transaction via `keyAuthorization`. The authorization is provisioned
as part of that transaction, so the user does not pay for it upfront.

:::code-group
```ts twoslash [example.ts]
import { Account, Actions, P256 } from 'viem/tempo'
import { client } from './viem.config'

const account = Account.fromSecp256k1('0x...')
const accessKey = Account.fromP256(P256.randomPrivateKey(), {
  access: account,
})

// 1. Sign the key authorization offline (no transaction sent).
const keyAuthorization = await Actions.accessKey.signAuthorization(client, {
  accessKey,
})

// 2. Attach it to the first transaction signed by the access key.
const { receipt } = await client.token.transferSync({
  account: accessKey,
  amount: 100n,
  keyAuthorization,
  to: '0xcafebabecafebabecafebabecafebabecafebabe',
  token: '0x20c0000000000000000000000000000000000001',
})
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

## Best Practices

### Use Non-Extractable Keys

Back access keys with a [WebCrypto or passkey account](/tempo/guides/accounts/create) so the
key material cannot be exported. The root key signs a single authorization, then the
non-extractable access key handles ongoing signing.

### Defer to Avoid Upfront Cost

When onboarding a user, prefer signing the authorization offline and attaching it to their first
transaction. This bundles provisioning into useful work instead of a standalone authorization
transaction.

## See More

<Cards>
  <Card icon="lucide:sliders-horizontal" title="Set Permissions & Limits" description="Restrict a key with an expiry, spending limits, and call scopes." to="/tempo/guides/access-keys/permissions" />

  <Card icon="lucide:settings" title="Manage Access Keys" description="Update limits, revoke keys, and inspect their onchain state." to="/tempo/guides/access-keys/manage" />

  <Card icon="lucide:shield-check" title="Admin Access Keys" description="Authorize unrestricted admin keys that can manage an account's other keys." to="/tempo/guides/access-keys/admin" />

  <Card icon="lucide:book-open" title="Tempo Docs: Access Keys" description="The full guide to authorizing and using access keys on Tempo." to="https://docs.tempo.xyz/guide/use-accounts/authorize-access-keys" />
</Cards>
