Every row below was verified against $(ask src better-auth)/packages/better-auth/src/plugins/ and each plugin's index.ts exports. Re-run this before trusting any import path for the version in use:
SRC=$(ask src better-auth)
ls "$SRC/packages/better-auth/src/plugins"
rg "^export (const|function) " "$SRC/packages/better-auth/src/plugins/*/index.ts"Plugins live in the main better-auth package unless marked otherwise. Each server plugin is added to betterAuth({ plugins: [...] }); each matching client plugin is added to createAuthClient({ plugins: [...] }) so the client SDK surfaces the new endpoints with types.
Server: import { organization } from "better-auth/plugins/organization"
Client: import { organizationClient } from "better-auth/client/plugins"
Adds orgs, members, roles, invitations, and team-scoped sessions. Ships a companion access-control module (access — see below) for defining role statements.
Use when the app has multiple tenants, workspaces, or teams. Skip for single-tenant apps with a flat user list.
Server: import { twoFactor } from "better-auth/plugins/two-factor"
Client: import { twoFactorClient } from "better-auth/client/plugins"
TOTP + backup codes + optional OTP. Adds /two-factor/* endpoints.
Server: import { passkey } from "@better-auth/passkey"
Client: import { passkeyClient } from "@better-auth/passkey/client"
WebAuthn passkey registration and sign-in. Not in better-auth/plugins/ — it ships as its own package. Confirm with ls $(ask src better-auth)/packages/passkey.
Server: import { magicLink } from "better-auth/plugins/magic-link"
Client: import { magicLinkClient } from "better-auth/client/plugins"
Passwordless email links. Requires providing sendMagicLink({ email, url, token }) — mail delivery is owned by the caller.
Server: import { emailOTP } from "better-auth/plugins/email-otp"
Client: import { emailOTPClient } from "better-auth/client/plugins"
Email OTP for verification / sign-in / password reset. Requires a sendVerificationOTP callback.
Server: import { phoneNumber } from "better-auth/plugins/phone-number"
Client: import { phoneNumberClient } from "better-auth/client/plugins"
Phone + OTP sign-in. Requires a sendOTP callback — pair with Twilio, Vonage, etc.
Server: import { siwe } from "better-auth/plugins/siwe"
Client: import { siweClient } from "better-auth/client/plugins"
Sign-In With Ethereum (EIP-4361). Needs getNonce / verifyMessage callbacks.
Server: import { oneTap } from "better-auth/plugins/one-tap"
Client: import { oneTapClient } from "better-auth/client/plugins"
Google One Tap sign-in.
Server: import { anonymous } from "better-auth/plugins/anonymous"
Client: import { anonymousClient } from "better-auth/client/plugins"
Creates throw-away users before sign-up; upgrades them to real accounts on credential linking.
Server: import { username } from "better-auth/plugins/username"
Client: import { usernameClient } from "better-auth/client/plugins"
Adds username field + username-based sign-in alongside email.
Server: import { genericOAuth } from "better-auth/plugins/generic-oauth"
Client: import { genericOAuthClient } from "better-auth/client/plugins"
Catch-all for OAuth 2 / OIDC providers not in social-providers/. Ships pre-built configs for Auth0, Slack, and more under plugins/generic-oauth/providers/ — enumerate with ls $(ask src better-auth)/packages/better-auth/src/plugins/generic-oauth/providers.
Server: import { oAuthProxy } from "better-auth/plugins/oauth-proxy"
Proxies OAuth callbacks through a stable production URL so preview deployments (Vercel previews, tunnels, etc.) can complete OAuth flows that require a fixed redirect URI. Reads productionURL or falls back to BETTER_AUTH_URL.
Server: import { oidcProvider } from "better-auth/plugins/oidc-provider"
Turns better-auth into an OIDC provider (the app hands out tokens to other apps). The inverse of social-providers.
Server: import { jwt } from "better-auth/plugins/jwt"
Issues signed JWTs alongside the session cookie — useful when other services need to verify sessions without a round-trip.
Server: import { bearer } from "better-auth/plugins/bearer"
Accepts Authorization: Bearer <token> in addition to cookies. Wire it up for API clients and mobile apps that can't carry cookies.
Server: import { multiSession } from "better-auth/plugins/multi-session"
Client: import { multiSessionClient } from "better-auth/client/plugins"
Lets a browser keep several concurrent sessions (switch between accounts without signing out).
Server: import { customSession } from "better-auth/plugins/custom-session"
Client: import { customSessionClient } from "better-auth/client/plugins"
Extend the shape returned by useSession() / getSession() — commonly used to embed the current organization on the session object.
Server: import { oneTimeToken } from "better-auth/plugins/one-time-token"
Client: import { oneTimeTokenClient } from "better-auth/client/plugins"
Short-lived single-use tokens (e.g. for invite links or password-less device linking).
Server: import { deviceAuthorization } from "better-auth/plugins/device-authorization"
Client: import { deviceAuthorizationClient } from "better-auth/client/plugins"
RFC 8628 device flow — pair a TV / CLI with a browser session.
Server: import { lastLoginMethod } from "better-auth/plugins/last-login-method"
Client: import { lastLoginMethodClient } from "better-auth/client/plugins"
Remembers the last auth method per user and exposes it so the UI can highlight it on the sign-in form.
Server: import { admin } from "better-auth/plugins/admin"
Client: import { adminClient } from "better-auth/client/plugins"
Role-based user management: list, ban, impersonate, set role. Pair with access for fine-grained statements.
import { createAccessControl, role } from "better-auth/plugins/access"
Not a plugin itself — the access-control primitive used by organization and admin to define role statements (resource × action).
Client-only type helper: import { inferAdditionalFields } from "better-auth/client/plugins"
Propagates extra columns added to the user / session / account tables through the client SDK's types.
Server: import { haveIBeenPwned } from "better-auth/plugins/haveibeenpwned"
Rejects sign-ups / password changes when the password appears in the HIBP k-anonymity API.
Server: import { captcha } from "better-auth/plugins/captcha"
Gates sensitive endpoints behind Turnstile / hCaptcha / reCAPTCHA / Arkose verification.
Server: import { openAPI } from "better-auth/plugins/open-api"
Exposes an OpenAPI 3 schema for every mounted endpoint (including plugin endpoints) — useful for client-SDK codegen.
Server: import { mcp } from "better-auth/plugins/mcp"
Model Context Protocol integration — lets an MCP client authenticate against better-auth. Ships MCP-specific adapters: mcpAuthHono, mcpAuthOfficial, mcpAuthMcpUse.
| User-visible need | Pick |
|---|---|
| Teams, orgs, workspaces | organization (+ customSession to surface active org) |
| TOTP / backup codes | two-factor |
| Passkeys / WebAuthn | @better-auth/passkey |
| Email magic link | magic-link |
| Email or SMS OTP | email-otp, phone-number |
| Remember Ethereum wallet | siwe |
| Admin panel for user management | admin (+ access) |
| API clients / mobile (no cookies) | bearer |
| Preview deploys / tunnels break OAuth | oauth-proxy |
| App acts as IdP | oidc-provider |
| Other services need signed claims | jwt |
| User switches between accounts | multi-session |
| Pwned-password blocklist | haveibeenpwned |
| Bot protection on sensitive endpoints | captcha |
| Auto-generated SDK / docs | open-api |
Most plugins add columns or tables. After enabling one, regenerate the schema:
npx auth generate # prints schema diff / writes files
npx auth migrate # applies (Kysely built-in only)Forgetting this step is the top cause of no such column / invalid input syntax errors at runtime. See references/common-errors.md ("schema drift").