diff --git a/docs/app/blog/_components/changelog-layout.tsx b/docs/app/blog/_components/changelog-layout.tsx
index 485b273949..ddb07f7fc9 100644
--- a/docs/app/blog/_components/changelog-layout.tsx
+++ b/docs/app/blog/_components/changelog-layout.tsx
@@ -1,5 +1,4 @@
import Link from "next/link";
-import { useId } from "react";
import clsx from "clsx";
import { DiscordLogoIcon } from "@radix-ui/react-icons";
@@ -91,21 +90,6 @@ export function IntroFooter() {
);
}
-export function SignUpForm() {
- let id = useId();
-
- return (
-
- );
-}
-
export function IconLink({
children,
className,
diff --git a/docs/app/blog/layout.tsx b/docs/app/blog/layout.tsx
index 3ce50d1d9c..8add5c2138 100644
--- a/docs/app/blog/layout.tsx
+++ b/docs/app/blog/layout.tsx
@@ -11,7 +11,17 @@ interface BlogLayoutProps {
export default function BlogLayout({ children }: BlogLayoutProps) {
return (
-
+
{children}
);
diff --git a/docs/app/changelogs/[[...slug]]/page.tsx b/docs/app/changelogs/[[...slug]]/page.tsx
index 52ddec8c0a..294c385451 100644
--- a/docs/app/changelogs/[[...slug]]/page.tsx
+++ b/docs/app/changelogs/[[...slug]]/page.tsx
@@ -18,10 +18,9 @@ import { Pre } from "fumadocs-ui/components/codeblock";
import { DocsBody } from "fumadocs-ui/page";
import ChangelogPage, { Glow } from "../_components/default-changelog";
import { IconLink } from "../_components/changelog-layout";
-import { BookIcon, GitHubIcon, XIcon } from "../_components/icons";
-import { DiscordLogoIcon } from "@radix-ui/react-icons";
+import { XIcon } from "../_components/icons";
import { StarField } from "../_components/stat-field";
-import { CalendarClockIcon } from "lucide-react";
+import { GridPatterns } from "../_components/grid-pattern";
const metaTitle = "Changelogs";
const metaDescription = "Latest changes , fixes and updates.";
@@ -49,44 +48,21 @@ export default async function Page({
-
-
-
+
+
+
+
+ {formatDate(date)}
+
+
+
{title}{" "}
-
-
+
{description}
-
-
-
-
- Documentation
-
-
- GitHub
-
-
- Community
-
-
-
+
+
BETTER-AUTH.
@@ -95,7 +71,7 @@ export default async function Page({
+ );
+}
+
+export { GridPatterns };
diff --git a/docs/content/blogs/1-3.mdx b/docs/content/blogs/1-3.mdx
new file mode 100644
index 0000000000..03025e9daf
--- /dev/null
+++ b/docs/content/blogs/1-3.mdx
@@ -0,0 +1,335 @@
+---
+title: "Better Auth 1.3"
+description: "SSO with SAML, Multi Team Support, Additional Fields for Organization, Performance and more."
+date: 2025-07-19
+author:
+ name: "Bereket Engida"
+ avatar: "/blogs/bereket.png"
+ twitter: "iambereket"
+image: "/release-og/1-3.png"
+tags: ["1.3", "authentication", "oidc", "mcp", "sso", "organization"]
+---
+
+## 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:
+
+```package-install
+npm install better-auth@1.3
+```
+
+---
+
+## 🚀 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](/docs/plugins/sso)
+
+```ts title="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](/docs/plugins/oidc)
+👉 [Read MCP docs](/docs/plugins/mcp)
+
+```ts title="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](/docs/plugins/stripe)
+
+
+```ts title="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](/docs/plugins/siwe)
+
+```ts title="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**.
+
+```ts title="auth.ts"
+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.
+
+
+```ts title="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**
+
+```ts title="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.
+
+```ts title="auth.ts"
+export const auth = betterAuth({
+ plugins: [
+ organization({
+ // ...
+ }),
+ ],
+});
+```
+
+---
+
+### **Additional Organization Fields**
+
+Add custom fields to `organization`, `member`, and `invitation` models.
+
+```ts title="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
+
+```ts title="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](https://github.com/better-auth/better-auth/releases/tag/v1.3.0)
+
+---
diff --git a/docs/public/release-og/1-3.png b/docs/public/release-og/1-3.png
new file mode 100644
index 0000000000..ee4c492184
Binary files /dev/null and b/docs/public/release-og/1-3.png differ
diff --git a/packages/better-auth/src/plugins/organization/adapter.ts b/packages/better-auth/src/plugins/organization/adapter.ts
index d1637952d0..d6e4062a3c 100644
--- a/packages/better-auth/src/plugins/organization/adapter.ts
+++ b/packages/better-auth/src/plugins/organization/adapter.ts
@@ -599,7 +599,15 @@ export const getOrgAdapter = (
return members;
},
-
+ countMembers: async (data: {
+ organizationId: string;
+ }) => {
+ const count = await adapter.count({
+ model: "member",
+ where: [{ field: "organizationId", value: data.organizationId }],
+ });
+ return count;
+ },
listTeamsByUser: async (data: {
userId: string;
}) => {
diff --git a/packages/better-auth/src/plugins/organization/routes/crud-members.ts b/packages/better-auth/src/plugins/organization/routes/crud-members.ts
index c096a66296..56caf91a5d 100644
--- a/packages/better-auth/src/plugins/organization/routes/crud-members.ts
+++ b/packages/better-auth/src/plugins/organization/routes/crud-members.ts
@@ -131,9 +131,9 @@ export const addMember = (option: O) => {
}
const membershipLimit = ctx.context.orgOptions?.membershipLimit || 100;
- const members = await adapter.listMembers({ organizationId: orgId });
+ const count = await adapter.countMembers({ organizationId: orgId });
- if (members.length >= membershipLimit) {
+ if (count >= membershipLimit) {
throw new APIError("FORBIDDEN", {
message:
ORGANIZATION_ERROR_CODES.ORGANIZATION_MEMBERSHIP_LIMIT_REACHED,