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) => () => voidWatches 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 | nullIf 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 configconfig } from "./config";
const const signerSubscription: () => voidsignerSubscription = function watchSignerStatus(config: AlchemyAccountsConfig): (onChange: (status: SignerStatus) => void) => () => voidWatches the signer status in the client store and triggers the provided callback function when the status changes.
watchSignerStatus(import configconfig)(async (status: SignerStatusstatus) => {
if (status: SignerStatusstatus.isConnected: booleanisConnected) {
const const signer: AlchemySigner | nullsigner = getSigner<AlchemySigner>(config: AlchemyAccountsConfig): AlchemySigner | nullIf 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 configconfig);
await const signer: AlchemySigner | nullsigner.BaseAlchemySigner<TClient extends BaseSignerClient>.addPasskey: (params?: CredentialCreationOptions) => Promise<string[]>Adds a passkey to the user's account
addPasskey();
}
});
import { const createConfig: (params: CreateConfigProps) => AlchemyAccountsConfigCreates 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): AlchemyTransportCreates 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: Chainsepolia } from "@account-kit/infra";
export const const config: AlchemyAccountsConfigconfig = function createConfig(params: CreateConfigProps): AlchemyAccountsConfigCreates 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: AlchemyTransporttransport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates 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: stringapiKey: "YOUR_API_KEY" }),
chain: Chainchain: const sepolia: Chainsepolia,
// optional if you want to sponsor gas
policyId?: string | string[] | undefinedpolicyId: "YOUR_POLICY_ID",
});