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.
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
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.
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.
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.
import { betterAuth } from "better-auth";
export const auth = betterAuth({
socialProviders: {
notion: { /* ... */ },
slack: { /* ... */ },
linear: { /* ... */ },
faceit: { /* ... */ },
},
});SvelteKit Cookie Helper Plugin
Utilities for handling cookies in SvelteKit server actions.
Breaking change: building and getRequestEvent must now be passed in as props.
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
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.
export const auth = betterAuth({
plugins: [
organization({
// ...
}),
],
});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.
export const auth = betterAuth({
plugins: [
organization({
schema: {
organization: { additionalFields: { /* ... */ } },
member: { additionalFields: { /* ... */ } },
invitation: { additionalFields: { /* ... */ } },
},
}),
],
});Other new options:
maximumMembersPerTeam– set team member limitslistUserInvitations– list all invitations for a user
Generic OAuth Improvements
- Added support for extra token URL params
- OAuth token encryption options
export const auth = betterAuth({
plugins: [
genericOAuth({
// ...
}),
],
});API Keys
requireNameoption for key creationverifyKeynow 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 inferAuthutility to infer types from the client- Improved docs with
authandauthClientexamples rememberMesupport insignUpafterEmailVerificationhookfreshAgeand customerrorURLrespected 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
ctxin hooks - Proper error when removing invalid user IDs
- Fixed missing
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
callbackURLinsignInUsername - Allow account linking without email
- Fixed missing
nulltype in/get-sessionresponse - Global
onSuccesshook 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
serialas PK ifuseNumberIdis enabled
Email & OTP
- OTPs now encrypted
- Fixed
onEmailVerificationnot 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_accessno longer requiresprompt=consent - Fixed malformed base64 encoding for token validation
A lot of refinements to make everything smoother, faster, and more reliable. 👉 Check the full changelog