Configure the relying-party domain, schema, browser client, and account security controls before verifying enrollment and recovery.

Passkey support in BTST connects a Better Auth server plugin, a browser plugin, and the account security interface. The UI flag reveals the controls; the server verifies registration and sign-in against your application's domain and origin.
This guide targets @btst/better-auth-ui@2.0.0, Better Auth 1.6.16, and @better-auth/passkey@1.6.16. It extends the existing auth integration. Keep the compatible dependency group together rather than independently upgrading one auth package.
A passkey belongs to a relying party, identified by a domain. For an application served entirely from https://app.example.com, add this plugin to the existing server configuration:
import { passkey } from "@better-auth/passkey";
export const passkeyPlugin = passkey({
rpID: "app.example.com",
rpName: "Example App",
origin: "https://app.example.com",
});
Append passkeyPlugin to betterAuth({ plugins: [...] }), preserving your database, existing auth methods, trusted origins, and handler. Replace the example values with the actual deployed configuration. rpID is a hostname without a scheme, port, or path; origin includes the scheme and any nondefault port, with no route path or trailing slash.
For a local app at http://localhost:3000, use rpID: "localhost" and origin: "http://localhost:3000". Treat production and development credentials as separate. Do not assume a passkey created for one domain will work on an unrelated preview hostname. Choose the production domain before enrolling users; a domain change needs a deliberate migration and recovery plan.
The Better Auth passkey options describe the domain and origin configuration. Browser Web Authentication uses public-key credentials and requires a secure context, with local development exceptions. The application does not receive a fingerprint or face scan; the authenticator handles its local verification method.
The passkey plugin stores credential records. Generate the schema with the Better Auth tooling matching your installed release, review the resulting changes, and apply them through your existing database migration process. Confirm the auth adapter points to the updated schema before exposing enrollment.
Adding a client button does not create this table. A missing-table error during registration is a database configuration problem, not a reason to remove server checks. Keep migrations specific to the intended environment and preserve existing account, session, and credential data.
Add the passkey client plugin to the same auth client BTST uses:
import { createAuthClient } from "better-auth/react";
import { passkeyClient } from "@better-auth/passkey/client";
export const authClient = createAuthClient({
plugins: [passkeyClient()],
});
This is a minimal fragment. Preserve other plugins and your configured API origin or base path. Then merge this into StackProvider's existing overrides.auth configuration:
import type { AuthPluginOverrides } from "@btst/better-auth-ui/client";
export const passkeyUI = {
passkey: true,
} satisfies Partial<AuthPluginOverrides>;
The released security page includes the passkey card when this option is enabled. With default paths and a /p site mount, open /p/account/security after signing in through an existing method. The card lists registered credentials and calls authClient.passkey.addPasskey when adding one.
Enrollment normally requires a fresh session. The companion checks its freshAge before opening the browser prompt; the server separately enforces its session freshness requirement. Keep the UI age aligned with your existing server session.freshAge policy. If enrollment asks for a new sign-in, reauthenticate through a supported method rather than weakening the server requirement.
The sign-in button calls authClient.signIn.passkey. Successful authentication then uses the provider's normal success transition. Preserve session refresh and backend permission checks; possessing a credential does not grant every application role.
Use a controlled account on the actual intended origin:
| Symptom | First checks |
|---|---|
| No passkey button or card | passkey override and the mounted auth/account pages |
| Client method is missing | passkeyClient() on the provider's actual client |
| Enrollment rejected before the prompt | Session presence, freshness, database schema |
| Origin or relying-party error | Browser address, configured origin, RP ID, preview hostname |
| Prompt cancelled or no credential available | Browser/authenticator support and an existing recovery method |
Support and credential synchronization vary by browser, operating system, authenticator, and user settings. Keep recovery usable and verify your deployment with representative devices. The configuration snippets were type-checked; no physical-authenticator or production enrollment round trip was performed for this article.
Continue with the BTST auth documentation and the session-management guide to check what happens after sign-in or revocation.