docs: v1.3 announcement changelog (#3476)

* v1.3 init anouncement changelog docs

* revamp on guide

* stale

* saml

* code block

* update

* update

* revamp and update

* feat: changelog image

* docs and og image

* revert

* update

* v1.3

* cont

* init

* update

* chore add count method

* update og

* update og

---------

Co-authored-by: Kinfe123 <kinfishtech@gmail.com>
This commit is contained in:
Bereket Engida
2025-07-19 12:51:15 -07:00
committed by GitHub
parent 28c846a7cc
commit dd7a158d47
8 changed files with 393 additions and 58 deletions

View File

@@ -1,5 +1,4 @@
import Link from "next/link"; import Link from "next/link";
import { useId } from "react";
import clsx from "clsx"; import clsx from "clsx";
import { DiscordLogoIcon } from "@radix-ui/react-icons"; import { DiscordLogoIcon } from "@radix-ui/react-icons";
@@ -91,21 +90,6 @@ export function IntroFooter() {
); );
} }
export function SignUpForm() {
let id = useId();
return (
<form className="relative isolate mt-8 flex items-center pr-1">
<label htmlFor={id} className="sr-only">
Email address
</label>
<div className="absolute inset-0 -z-10 rounded-lg transition peer-focus:ring-4 peer-focus:ring-sky-300/15" />
<div className="absolute inset-0 -z-10 rounded-lg bg-white/2.5 ring-1 ring-white/15 transition peer-focus:ring-sky-300" />
</form>
);
}
export function IconLink({ export function IconLink({
children, children,
className, className,

View File

@@ -11,7 +11,17 @@ interface BlogLayoutProps {
export default function BlogLayout({ children }: BlogLayoutProps) { export default function BlogLayout({ children }: BlogLayoutProps) {
return ( return (
<div className="relative flex min-h-screen flex-col"> <div
className="relative flex min-h-screen flex-col"
style={{
scrollbarWidth: "none",
scrollbarColor: "transparent transparent",
//@ts-expect-error
"&::-webkit-scrollbar": {
display: "none",
},
}}
>
<main className="flex-1">{children}</main> <main className="flex-1">{children}</main>
</div> </div>
); );

View File

@@ -18,10 +18,9 @@ import { Pre } from "fumadocs-ui/components/codeblock";
import { DocsBody } from "fumadocs-ui/page"; import { DocsBody } from "fumadocs-ui/page";
import ChangelogPage, { Glow } from "../_components/default-changelog"; import ChangelogPage, { Glow } from "../_components/default-changelog";
import { IconLink } from "../_components/changelog-layout"; import { IconLink } from "../_components/changelog-layout";
import { BookIcon, GitHubIcon, XIcon } from "../_components/icons"; import { XIcon } from "../_components/icons";
import { DiscordLogoIcon } from "@radix-ui/react-icons";
import { StarField } from "../_components/stat-field"; import { StarField } from "../_components/stat-field";
import { CalendarClockIcon } from "lucide-react"; import { GridPatterns } from "../_components/grid-pattern";
const metaTitle = "Changelogs"; const metaTitle = "Changelogs";
const metaDescription = "Latest changes , fixes and updates."; const metaDescription = "Latest changes , fixes and updates.";
@@ -49,44 +48,21 @@ export default async function Page({
<div className="bg-gradient-to-tr hidden md:block overflow-hidden px-12 py-24 md:py-0 -mt-[100px] md:h-dvh relative md:sticky top-0 from-transparent dark:via-stone-950/5 via-stone-100/30 to-stone-200/20 dark:to-transparent/10"> <div className="bg-gradient-to-tr hidden md:block overflow-hidden px-12 py-24 md:py-0 -mt-[100px] md:h-dvh relative md:sticky top-0 from-transparent dark:via-stone-950/5 via-stone-100/30 to-stone-200/20 dark:to-transparent/10">
<StarField className="top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2" /> <StarField className="top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2" />
<Glow /> <Glow />
<GridPatterns />
<div className="flex flex-col md:justify-center max-w-xl mx-auto h-full"> <div className="z-20 flex flex-col md:justify-center max-w-xl mx-auto h-full">
<h1 className="mt-14 font-sans font-semibold tracking-tighter text-5xl"> <div className="mt-14 mb-2 text-gray-600 dark:text-gray-300 flex items-center gap-x-1">
<p className="text-[12px] uppercase font-mono">
{formatDate(date)}
</p>
</div>
<h1 className=" font-sans mb-2 font-semibold tracking-tighter text-5xl">
{title}{" "} {title}{" "}
</h1> </h1>
<p className="text-sm text-gray-600 mb-2 dark:text-gray-300">
<p className="text-sm text-gray-600 dark:text-gray-300">
{description} {description}
</p> </p>
<div className="text-gray-600 dark:text-gray-300 flex items-center gap-x-1"> <hr className="mt-4" />
<CalendarClockIcon className="w-4 h-4" /> <p className="absolute bottom-10 text-[0.8125rem]/6 text-gray-500">
<p>{formatDate(date)}</p>
</div>
<hr className="h-px bg-gray-300 mt-5" />
<div className="mt-8 flex flex-wrap text-gray-600 dark:text-gray-300 gap-x-1 gap-y-3 sm:gap-x-2">
<IconLink
href="/docs"
icon={BookIcon}
className="flex-none text-gray-600 dark:text-gray-300"
>
Documentation
</IconLink>
<IconLink
href="https://github.com/better-auth/better-auth"
icon={GitHubIcon}
className="flex-none text-gray-600 dark:text-gray-300"
>
GitHub
</IconLink>
<IconLink
href="https://discord.gg/better-auth"
icon={DiscordLogoIcon}
className="flex-none text-gray-600 dark:text-gray-300"
>
Community
</IconLink>
</div>
<p className="flex items-baseline absolute bottom-4 max-md:left-1/2 max-md:-translate-x-1/2 gap-x-2 text-[0.8125rem]/6 text-gray-500">
<IconLink href="https://x.com/better_auth" icon={XIcon} compact> <IconLink href="https://x.com/better_auth" icon={XIcon} compact>
BETTER-AUTH. BETTER-AUTH.
</IconLink> </IconLink>
@@ -95,7 +71,7 @@ export default async function Page({
</div> </div>
<div className="px-4 relative md:px-8 pb-12 md:py-12"> <div className="px-4 relative md:px-8 pb-12 md:py-12">
<div className="absolute top-0 left-0 h-full -translate-x-full w-px bg-gradient-to-b from-black/5 dark:from-white/10 via-black/3 dark:via-white/5 to-transparent"></div> <div className="absolute top-0 left-0 h-full -translate-x-full w-px bg-gradient-to-b from-black/5 dark:from-white/10 via-black/3 dark:via-white/5 to-transparent"></div>
<DocsBody> <DocsBody className="pt-8 md:pt-0">
<MDX <MDX
components={{ components={{
...defaultMdxComponents, ...defaultMdxComponents,

View File

@@ -0,0 +1,22 @@
"use client";
import { cn } from "@/lib/utils";
function GridPatterns() {
return (
<div
className={cn(
"pointer-events-none",
"fixed inset-y-0 left-0 z-0",
"w-1/2 h-full",
"overflow-hidden",
)}
aria-hidden="true"
>
<div className="absolute opacity-40 inset-0 w-full h-full bg-[radial-gradient(circle_at_center,rgba(0,0,0,0.04)_1px,transparent_1px)] dark:bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.04)_1px,transparent_1px)] bg-[length:8px_8px]" />
<div className="absolute top-0 left-0 w-full h-full bg-gradient-to-br opacity-40 from-white/40 via-transparent to-white/10 dark:from-white/10 dark:to-transparent mix-blend-screen" />
</div>
);
}
export { GridPatterns };

335
docs/content/blogs/1-3.mdx Normal file
View File

@@ -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 productionready.
✅ 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 **SignIn 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**
Weve 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.
<Callout type="warn">
Breaking change: `building` and `getRequestEvent()` must now be passed in as props.
</Callout>
```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 SignIn**
```ts title="auth.ts"
export const auth = betterAuth({
emailVerification: {
sendOnSignIn: true, // sends a verification email on signin if the user isnt verified
},
});
```
---
### **MultiTeam 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 signup is disabled
* Phone number: Reset clears verification values
#### Two-Factor Auth
* Default OTP period fix
* URI generation doesnt 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)
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 KiB

View File

@@ -599,7 +599,15 @@ export const getOrgAdapter = <O extends OrganizationOptions>(
return members; 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: { listTeamsByUser: async (data: {
userId: string; userId: string;
}) => { }) => {

View File

@@ -131,9 +131,9 @@ export const addMember = <O extends OrganizationOptions>(option: O) => {
} }
const membershipLimit = ctx.context.orgOptions?.membershipLimit || 100; 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", { throw new APIError("FORBIDDEN", {
message: message:
ORGANIZATION_ERROR_CODES.ORGANIZATION_MEMBERSHIP_LIMIT_REACHED, ORGANIZATION_ERROR_CODES.ORGANIZATION_MEMBERSHIP_LIMIT_REACHED,