Better Auth is a TypeScript-first authentication framework. Session-based auth, OAuth, 2FA, organizations — with a plugin system and auto-generated client.
Why Better Auth?
- TypeScript-first — auto-generated typed client from server config
- Framework agnostic — Next.js, Nuxt, SvelteKit, Hono, Express
- Plugins — 2FA, organizations, magic link, passkey — add with one line
- Self-hosted — runs on YOUR server with YOUR database
Quick Start
npm install better-auth
// auth.ts
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: 'pg' }),
emailAndPassword: { enabled: true },
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
});
Client (Auto-Generated Types!)
// auth-client.ts
import { createAuthClient } from 'better-auth/react';
export const authClient = createAuthClient({
baseURL: 'http://localhost:3000',
});
// Usage in React
function LoginPage() {
const { signIn, signUp } = authClient;
const handleLogin = async () => {
await signIn.email({ email: 'alice@example.com', password: 'secret' });
};
const handleOAuth = async () => {
await signIn.social({ provider: 'github' });
};
const handleSignUp = async () => {
await signUp.email({
email: 'alice@example.com',
password: 'secret',
name: 'Alice',
});
};
}
Session Hook
function Dashboard() {
const { data: session, isPending } = authClient.useSession();
if (isPending) return <Loading />;
if (!session) return <Redirect to="/login" />;
return <h1>Welcome, {session.user.name}!</h1>;
}
Plugins
import { betterAuth } from 'better-auth';
import { twoFactor } from 'better-auth/plugins/two-factor';
import { organization } from 'better-auth/plugins/organization';
import { magicLink } from 'better-auth/plugins/magic-link';
export const auth = betterAuth({
// ...
plugins: [
twoFactor(),
organization(),
magicLink({ sendMagicLink: async ({ email, url }) => {
await sendEmail(email, 'Login Link', `Click here: ${url}`);
}}),
],
});
Next.js Integration
// app/api/auth/[...all]/route.ts
import { auth } from '@/auth';
import { toNextJsHandler } from 'better-auth/next-js';
export const { GET, POST } = toNextJsHandler(auth);
Middleware
// middleware.ts
import { auth } from '@/auth';
export async function middleware(request: NextRequest) {
const session = await auth.api.getSession({ headers: request.headers });
if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
}
Building authenticated apps? Check out my Apify actors for web scraping, or email spinov001@gmail.com for custom auth solutions.
Better Auth, Clerk, or Auth.js — which auth library do you use? Share below!
Top comments (0)