BETTER-AUTH. UI
Plugins

Passkey

Add passwordless passkey sign-in and device management to your authentication flow.

The passkey plugin adds passwordless authentication using WebAuthn. Users can sign in with their device authenticator (Touch ID, Face ID, Windows Hello) and manage registered passkeys from their security settings.

It contributes:

  • A "Continue with Passkey" button rendered on the sign-in and magic-link views (hidden on sign-up)
  • A <Passkeys /> security card for listing, adding, and deleting registered passkeys
  • useSignInPasskey, useAddPasskey, useDeletePasskey, and useListPasskeys hooks

Setup

Install the Better Auth plugin

Install the @better-auth/passkey package and add it to your Better Auth server config:

lib/auth.ts
import { betterAuth } from "better-auth"
import { passkey } from "@better-auth/passkey"

export const auth = betterAuth({
  // ...
  plugins: [
    passkey() 
  ]
})

Install the matching client plugin

Add passkeyClient() to your auth client so authClient.signIn.passkey and authClient.passkey.* are available:

lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
import { passkeyClient } from "@better-auth/passkey/client"

export const authClient = createAuthClient({
  plugins: [passkeyClient()] 
})

Install the UI plugin

Run the shadcn CLI to install the passkey button, passkey management card, and the passkeyPlugin() factory into your project:

npx shadcn@latest add https://better-auth-ui.com/r/passkey.json

This drops the following into your codebase:

  • src/lib/auth/auth-plugin.ts — local AuthPlugin typing widener
  • src/lib/auth/passkey-plugin.tspasskeyPlugin() factory
  • src/components/auth/passkey/passkey-button.tsx — the "Continue with Passkey" sign-in button
  • src/components/auth/passkey/passkeys.tsx — the passkey management card
  • src/components/auth/passkey/passkey.tsx — individual passkey row
  • src/components/auth/passkey/passkey-skeleton.tsx — skeleton shown while passkeys load
  • src/components/auth/passkey/passkeys-empty.tsx — empty state shown when no passkeys exist
  • src/components/auth/passkey/add-passkey-dialog.tsx — dialog for registering a new passkey
  • src/components/auth/passkey/delete-passkey-dialog.tsx — confirmation dialog for revoking a passkey

Register the plugin

Pass passkeyPlugin() to <AuthProvider>:

components/providers.tsx
import { passkeyPlugin } from "@/lib/auth/passkey-plugin"
import { AuthProvider } from "@/components/auth/auth-provider"

<AuthProvider
  authClient={authClient}
  navigate={navigate}
  plugins={[passkeyPlugin()]} 
>
  {children}
</AuthProvider>

Components

<SignIn />

Sign In
OR
Forgot password?

Need to create an account? Sign Up

A "Continue with Passkey" button is automatically rendered on the <SignIn /> and <MagicLink /> views when the plugin is registered (hidden on sign-up).

Usage

import { PasskeyButton } from "@/components/auth/passkey/passkey-button"

<PasskeyButton />

Props

Prop

Type

<Passkeys />

Passkeys

The <Passkeys /> security card is rendered on the security settings page when your layout renders each plugin's securityCards (as the example SecuritySettings does) and passkeyPlugin() is in plugins.

Usage

import { Passkeys } from "@/components/auth/passkey/passkeys"

<Passkeys />

Props

Prop

Type

Options

passkeyPlugin({
  // Override any of the plugin's localization strings.
  localization: {
    passkeys: "Security Keys"
  }
})

Prop

Type

Localization

Prop

Type

Last updated on

On this page