Add Passkey

You may have noticed in the Authenticate users guide, that it’s possible to authenticate users with a passkey they’ve already created. If you don’t want users to have to type in an email to log in with a passkey, this guide will cover how to add a passkey to a user’s account once they have already logged in.

Authenticate the user

See the Authenticate users guide for more information on how to authenticate a user with email. The user must be authenticated before you can add a passkey to their account

Add a passkey

Once the user is authenticated, you can use the addPasskey method on the Alchemy Signer. In the below example, we add the passkey as soon as the signer is connected. However, you can choose to add a passkey when the user clicks a button or at any other time. In this case, use the watchSignerStatus method to change your UI based on the signer’s connected status.

import { 
const watchSignerStatus: (config: AlchemyAccountsConfig) => (onChange: (status: SignerStatus) => void) => () => void

Watches the signer status in the client store and triggers the provided callback function when the status changes.

watchSignerStatus
,
const getSigner: <T extends AlchemySigner>(config: AlchemyAccountsConfig) => T | null

If there is a signer attached to the client state, it will return it. The signer should always be null on the server, and will be set on the client if the store was properly hydrated.

getSigner
} from "@account-kit/core";
import {
import config
config
} from "./config";
const
const signerSubscription: () => void
signerSubscription
=
function watchSignerStatus(config: AlchemyAccountsConfig): (onChange: (status: SignerStatus) => void) => () => void

Watches the signer status in the client store and triggers the provided callback function when the status changes.

watchSignerStatus
(
import config
config
)(async (
status: SignerStatus
status
) => {
if (
status: SignerStatus
status
.
isConnected: boolean
isConnected
) {
const
const signer: AlchemySigner | null
signer
=
getSigner<AlchemySigner>(config: AlchemyAccountsConfig): AlchemySigner | null

If there is a signer attached to the client state, it will return it. The signer should always be null on the server, and will be set on the client if the store was properly hydrated.

getSigner
(
import config
config
);
await
const signer: AlchemySigner | null
signer
.
BaseAlchemySigner<TClient extends BaseSignerClient>.addPasskey: (params?: CredentialCreationOptions) => Promise<string[]>

Adds a passkey to the user's account

addPasskey
();
} });
import { 
const createConfig: (params: CreateConfigProps) => AlchemyAccountsConfig

Creates an AlchemyAccountsConfig object that can be used in conjunction with the actions exported from @account-kit/core.

The config contains core and client stores that can be used to manage account state in your application.

createConfig
} from "@account-kit/core";
import {
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
,
const sepolia: Chain
sepolia
} from "@account-kit/infra";
export const
const config: AlchemyAccountsConfig
config
=
function createConfig(params: CreateConfigProps): AlchemyAccountsConfig

Creates an AlchemyAccountsConfig object that can be used in conjunction with the actions exported from @account-kit/core.

The config contains core and client stores that can be used to manage account state in your application.

createConfig
({
transport: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
({
apiKey: string
apiKey
: "YOUR_API_KEY" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
// optional if you want to sponsor gas
policyId?: string | string[] | undefined
policyId
: "YOUR_POLICY_ID",
});