# Sign In with a Passkey

## Overview

Passkeys let users sign in and authorize transactions with a WebAuthn credential (such as Face
ID, Touch ID, or a hardware key) instead of a private key. The credential is bound to the
user's device and origin, so there is no seed phrase to manage. Tempo passkey accounts are
created with [`Account.fromWebAuthnP256`](/tempo/accounts/account.fromWebAuthnP256).

## Recipes

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

### Create a Passkey Account

Create a credential with [`WebAuthnP256.createCredential`](/tempo/accounts/account.fromWebAuthnP256),
instantiate the account, then persist the credential's public key for later use.

```ts twoslash
// @noErrors
import { Account, WebAuthnP256 } from 'viem/tempo'
import { store } from './store'

// 1. Create the credential.
const credential = await WebAuthnP256.createCredential({ name: 'Example' })

// 2. Instantiate the account.
const account = Account.fromWebAuthnP256(credential)

// 3. Persist the public key (required to restore the account later).
await store.set(credential.id, credential.publicKey)
```

### Restore a Passkey Account

Load an existing credential with `WebAuthnP256.getCredential`. The address is derived from the
public key, so provide a `getPublicKey` function that reads it back from your store.

```ts twoslash
// @noErrors
import { Account, WebAuthnP256 } from 'viem/tempo'
import { store } from './store'

// 1. Get the credential, resolving the public key from your store.
const credential = await WebAuthnP256.getCredential({
  async getPublicKey(credential) {
    return await store.get(credential.id)
  },
})

// 2. Instantiate the account.
const account = Account.fromWebAuthnP256(credential)
```

### Send a Transaction with a Passkey

Pass the passkey account to any Action that accepts an `account`. The user is prompted to
authorize with their passkey when the transaction is signed.

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

const credential = await WebAuthnP256.createCredential({ name: 'Example' })
const account = Account.fromWebAuthnP256(credential)

const receipt = await client.sendTransactionSync({
  account, // [!code focus]
  data: '0xdeadbeef',
  to: '0xcafebabecafebabecafebabecafebabecafebabe',
})
```

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

## Best Practices

### Persist the Public Key

A passkey only stores its credential id on the device, not the public key. Because the account
address is derived from the public key, you must store it yourself (in a database or local
storage) when the credential is created, then resolve it via `getPublicKey` when restoring.

### Pair with Access Keys

Passkeys prompt the user on every signature. For repeated transactions without a prompt,
authorize an [Access Key](/tempo/guides/access-keys) once with the passkey, then sign
subsequent transactions with the access key.

## See More

<Cards>
  <Card icon="lucide:wallet" title="Create an Account" description="Create Tempo accounts from private keys, passkeys, or device-bound keys." to="/tempo/guides/accounts/create" />

  <Card icon="lucide:key-round" title="Access Keys" description="Authorize a secondary key to sign without a passkey prompt each time." to="/tempo/guides/access-keys" />

  <Card icon="lucide:square-function" title="Account.fromWebAuthnP256" description="The full API reference for WebAuthn passkey accounts." to="/tempo/accounts/account.fromWebAuthnP256" />
</Cards>
