Embed Passkey Accounts
Create a domain-bound passkey account on Tempo using WebAuthn signatures for secure, passwordless authentication with Tempo transactions.
Passkeys enable users to authenticate with biometrics (fingerprint, Face ID, Touch ID) they already use for other apps. Keys are stored in the device's secure enclave and sync across devices via iCloud Keychain or Google Password Manager.
Demo
By the end of this guide, you will be able to embed passkey accounts into your application.
Passkey Accounts
demoSteps
Set up Wagmi
Ensure that you have set up your project with Wagmi by following the guide.
Configure the WebAuthn Connector
Next, we will need to configure the webAuthn connector in our Wagmi config.
import { createConfig, http } from 'wagmi'
import { tempo } from 'tempo.ts/chains'
import { KeyManager, webAuthn } from 'tempo.ts/wagmi'
export const config = createConfig({
chains: [tempo({ feeToken: '0x20c0000000000000000000000000000000000001' })],
connectors: [webAuthn({
keyManager: KeyManager.localStorage(),
})],
multiInjectedProviderDiscovery: false,
transports: {
[tempo.id]: http(),
},
})Display Sign In Buttons
After that, we will set up "Sign in" and "Sign up" buttons so that the user can create or use a passkey with the application.
We will create a new Example.tsx component to work in.
import { useConnect, useConnectors } from 'wagmi'
export function Example() {
const connect = useConnect()
const [connector] = useConnectors()
return (
<div>
<button
onClick={() =>
connect.connect({
connector,
capabilities: { type: 'sign-up' },
})
}
>
Sign up
</button>
<button onClick={() => connect.connect({ connector })}>
Sign in
</button>
</div>
)
}Display Account & Sign Out
After the user has signed in, we can display the account information and a sign out button.
import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi'
export function Example() {
const account = useConnection()
const connect = useConnect()
const [connector] = useConnectors()
const disconnect = useDisconnect()
if (account.address)
return (
<div>
<div>{account.address.slice(0, 6)}...{account.address.slice(-4)}</div>
<button onClick={() => disconnect.disconnect()}>Sign out</button>
</div>
)
return (
<div>
<button
onClick={() =>
connect.connect({
connector,
capabilities: { type: 'sign-up' },
})
}
>
Sign up
</button>
<button onClick={() => connect.connect({ connector })}>
Sign in
</button>
</div>
)
}Next Steps
Now that you have created your first passkey account, you can now:
- learn the Best Practices below
- follow a guide on how to make a payment, create a stablecoin, and more with a passkey account.
Best Practices
Loading State
When the user is logging in or signing out, we should show loading state to indicate that the process is happening.
We can use the isPending property from the useConnect hook to show pending state to the user.
import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi'
export function Example() {
const account = useConnection()
const connect = useConnect()
const [connector] = useConnectors()
const disconnect = useDisconnect()
if (connect.isPending)
return <div>Check prompt...</div>
return (/* ... */)
}Error Handling
If an error unexpectedly occurs, we should display an error message to the user.
We can use the error property from the useConnect hook to show error state to the user.
import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi'
export function Example() {
const account = useConnection()
const connect = useConnect()
const [connector] = useConnectors()
const disconnect = useDisconnect()
if (connect.error)
return <div>Error: {connect.error.message}</div>
return (/* ... */)
}