Example Docs

Plugins

Better Auth's plugin system lets you add powerful features without bloating the core. Each plugin is self-contained with its own database schema, API endpoints, and client-side utilities.

How Plugins Work

Plugins hook into Better Auth's lifecycle:

import { betterAuth } from "better-auth";
import { twoFactor } from "better-auth/plugins";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    twoFactor({
      issuer: "MyApp",
    }),
    organization({
      allowUserToCreateOrganization: true,
    }),
  ],
});

Each plugin can:

Available Plugins

Authentication

PluginDescription
Two FactorTOTP, SMS, and backup codes
PasskeyWebAuthn / FIDO2 passwordless authentication
Magic LinkPasswordless email authentication
Phone NumberSMS-based authentication
AnonymousAllow anonymous/guest users

Authorization & Access Control

PluginDescription
OrganizationsMulti-tenant organization management
AdminAdmin dashboard and user management
RBACRole-based access control

Enterprise

PluginDescription
OIDC ProviderTurn your app into an OpenID Connect provider
SAMLEnterprise SSO with SAML 2.0
SCIMAutomated user provisioning

Utilities

PluginDescription
Rate LimitAdvanced rate limiting rules
CaptchaBot protection with CAPTCHA
WebhookReal-time auth event notifications

Client-Side Plugin Setup

Plugins that add client-side features need to be registered on the auth client too:

import { createAuthClient } from "better-auth/react";
import { twoFactorClient } from "better-auth/client/plugins";
import { organizationClient } from "better-auth/client/plugins";

export const authClient = createAuthClient({
  plugins: [twoFactorClient(), organizationClient()],
});

Creating Custom Plugins

You can build your own plugins:

import { createAuthPlugin } from "better-auth";

export const myPlugin = createAuthPlugin({
  id: "my-plugin",
  init: (ctx) => {
    return {
      endpoints: {
        myEndpoint: {
          path: "/my-plugin/action",
          method: "POST",
          handler: async (req) => {
            // Your custom logic
            return { success: true };
          },
        },
      },
      hooks: {
        after: [
          {
            matcher: (ctx) => ctx.path === "/sign-in",
            handler: async (ctx) => {
              // Run after sign-in
              console.log("User signed in:", ctx.session.user.name);
            },
          },
        ],
      },
    };
  },
});

Deep Dives