DEV Community

Alex Spinov
Alex Spinov

Posted on

Better Auth Has a Free API — TypeScript Authentication That Just Works

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
Enter fullscreen mode Exit fullscreen mode
// 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!,
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

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',
    });
  };
}
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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}`);
    }}),
  ],
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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));
  }
}
Enter fullscreen mode Exit fullscreen mode

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)