Better Auth 1.3 Release

We're excited to announce the release of Better Auth 1.3. This release includes a lot of new features and improvements.

To upgrade, run:

npm install [email protected]

🚀 Highlights

SSO Plugin

The SSO plugin has been moved to its own package and now supports both OIDC and SAML 2.0.

👉 Read the SSO docs

auth.ts
import { betterAuth } from "better-auth";
import { sso } from "@better-auth/sso";
 
export const auth = betterAuth({
  plugins: [
    sso({
      oidc: {
        clientId: process.env.OIDC_CLIENT_ID!,
        clientSecret: process.env.OIDC_CLIENT_SECRET!,
      },
      saml: {
        entryPoint: "https://example.com/saml",
        issuer: "better-auth-example",
        certificate: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
      },
      providersLimit: async (user) => {
        const plan = await getUserPlan(user);
        return plan.name === "pro" ? 10 : 1;
      },
    }),
  ],
});

OIDC & MCP Plugins – Now Stable

Both OIDC and MCP plugins are production‑ready.

✅ Features:

  • Refresh token support in discovery & token endpoints
  • JWKs and PKCE for public clients
  • Trusted clients
  • Encrypted & hashed client secrets

👉 Read OIDC docs 👉 Read MCP docs

auth.ts
import { mcp } from "better-auth/plugins";
 
export const auth = betterAuth({
  plugins: [
    mcp({
      loginPage: "/login",
    }),
  ],
});

Stripe Plugin is now production ready

The Stripe plugin is now stable and usage based pricing is coming very soon.

👉 Read Stripe docs

auth.ts
import { betterAuth } from "better-auth";
import { stripe } from "@better-auth/stripe";
 
export const auth = betterAuth({
  plugins: [
    stripe({
      // ...
    }),
  ],
});

SIWE Plugin

Native support for Sign‑In with Ethereum.

👉 Read SIWE docs

auth.ts
import { siwe } from "better-auth/plugins";
 
export const auth = betterAuth({
  plugins: [
    siwe(),
  ],
});

New Social Providers

We’ve added providers for Notion, Slack, Linear, and Faceit.

auth.ts
import { betterAuth } from "better-auth";
 
export const auth = betterAuth({
  socialProviders: {
    notion: { /* ... */ },
    slack: { /* ... */ },
    linear: { /* ... */ },
    faceit: { /* ... */ },
  },
});

Utilities for handling cookies in SvelteKit server actions.

Breaking change: building and getRequestEvent() must now be passed in as props.

auth.ts
import { betterAuth } from "better-auth";
import { sveltekitCookies } from "better-auth/svelte-kit";
import { getRequestEvent } from "$app/server";
 
export const auth = betterAuth({
  plugins: [sveltekitCookies(getRequestEvent)],
});

Email Verification on Sign‑In

auth.ts
export const auth = betterAuth({
  emailVerification: {
    sendOnSignIn: true, // sends a verification email on sign‑in if the user isn’t verified
  },
});

Multi‑Team Support

The organization plugin now supports members belonging to multiple teams.

Breaking change: teamId has been removed from the member table. A new teamMembers table is required.

auth.ts
export const auth = betterAuth({
  plugins: [
    organization({
      // ...
    }),
  ],
});
auth-client.ts
import { createAuthClient } from "better-auth/client";
import { organizationClient } from "better-auth/client/plugins";
import { auth } from "./auth";
 
export const authClient = createAuthClient({
  // pass your auth instance to infer additional fields
  plugins: [organizationClient({ $inferAuth: {} as typeof auth })], 
});

Additional Organization Fields

Add custom fields to organization, member, and invitation models.

auth.ts
export const auth = betterAuth({
  plugins: [
    organization({
      schema: {
        organization: { additionalFields: { /* ... */ } },
        member: { additionalFields: { /* ... */ } },
        invitation: { additionalFields: { /* ... */ } },
      },
    }),
  ],
});

Other new options:

  • maximumMembersPerTeam – set team member limits
  • listUserInvitations – list all invitations for a user

Generic OAuth Improvements

  • Added support for extra token URL params
  • OAuth token encryption options
auth.ts
export const auth = betterAuth({
  plugins: [
    genericOAuth({
      // ...
    }),
  ],
});

API Keys

  • requireName option for key creation
  • verifyKey now supports async functions

Username

  • Availability checks
  • Custom normalization

✨ More Features

  • Migrated to Zod 4 for better type safety and performance
  • CLI supports custom adapter createSchema
  • inferAuth utility to infer types from the client
  • Improved docs with auth and authClient examples
  • rememberMe support in signUp
  • afterEmailVerification hook
  • freshAge and custom errorURL respected properly
  • OAuth2 tokens now include refresh_token_expires_in

🐛 Bug Fixes & Improvements

Plugins

  • Expo: Fixed type path import

  • SSO: Fixed SAML redirection & type checks

  • Dropbox: Token access type support

  • Stripe:

    • Prevent duplicate customers
    • Allow upgrading incomplete subscriptions
  • Admin:

    • Fixed missing ctx in hooks
    • Proper error when removing invalid user IDs

OAuth & Providers

  • Fixed duplicate OAuth registration
  • Improved Google/Microsoft scope handling
  • Fixed malformed error URLs in generic OAuth
  • Facebook: Better detection for limited token JWT
  • Twitter: Improved email verification logic

Core Authentication

  • Exclude current user from username uniqueness check
  • Support callbackURL in signInUsername
  • Allow account linking without email
  • Fixed missing null type in /get-session response
  • Global onSuccess hook now works
  • JWT: Alternate algorithms supported in JWKS
  • origin-check: Wildcard trusted origins supported

CLI, DB, and Adapters

  • CLI: Improved Drizzle schema formatting
  • MongoAdapter: Works with create-adapter
  • Schema generation respects useNumberId
  • Postgres: Better varchar normalization and type comparison
  • Drizzle CLI: Uses serial as PK if useNumberId is enabled

Email & OTP

  • OTPs now encrypted
  • Fixed onEmailVerification not firing
  • Proper error when sign‑up is disabled
  • Phone number: Reset clears verification values

Two-Factor Auth

  • Default OTP period fix
  • URI generation doesn’t require enabling 2FA
  • Fixed OTP URI separator mismatch

Miscellaneous

  • Delete organization if member not found
  • Correct error codes for API key rate limits
  • Additional fields now show in OpenAPI
  • Fixed FK constraint generation for MySQL
  • Various improvements to account linking
  • OIDC offline_access no longer requires prompt=consent
  • Fixed malformed base64 encoding for token validation

A lot of refinements to make everything smoother, faster, and more reliable. 👉 Check the full changelog