Published on

Tanstack Start Better Auth Setup

Authors

Install NPM Package

Terminal
npm install better-auth@latest

Set Enviornment Variables

Generate the key with openssl.

Terminal
openssl rand -base64 32

Then set the environment variable.

.env
BETTER_AUTH_SECRET=<generated secret key>

Set the base URL.

.env
BETTER_AUTH_URL=http://localhost:3000

Create An Instance

src/lib/auth.ts
import { betterAuth } from "better-auth";
export const auth = betterAuth({
  //...
});

Add the Drizzle adapter.

src/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";

export const auth = betterAuth({
    database: drizzleAdapter(db, {
        provider: "pg",
    }),
});

Schema

I'm going to do some restructuring of the schema files to so that I can have a separate schema file for each model or use case such as auth.

Terminal
mkdir src/db/schema
touch src/db/schema/index.ts
touch src/db/schema/auth.schema.ts
echo 'export * from "./auth.schema.ts";' > src/db/schema/index.ts
rm src/db/schema.ts

Update src/db/index.ts.

src/db/index.ts
import { config } from "dotenv";

import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

import * as schema from "./schema";

config();

const pool = new Pool({
	connectionString: process.env.DATABASE_URL!,
});
export const db = drizzle(pool, { schema });

Update Drizzle config.

drizzle.config.ts
import { config } from 'dotenv'
import { defineConfig } from 'drizzle-kit'

config()

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL,
  },
})

Generate the required Better Auth schema.

Terminal
npx @better-auth/cli@latest generate --config ./src/lib/auth.ts -y --output ./src/db/schema/auth.schema.ts && prettier --write ./src/db/schema/auth.schema.ts

Delete the demo folder because todos schema no longer exists.

Terminal
rm -rf src/routes/demo

Generate the migration file.

Terminal
npx drzzle-kit generate

Run the migration.

Terminal
npx drizzle-kit migrate

Authentication Method

For this app I'm going to be using email and password authentication.

src/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";

export const auth = betterAuth({
	database: drizzleAdapter(db, {
		provider: "pg",
	}),
	emailAndPassword: {
		enabled: true,
	},
});

Mount Handler

Create a catch-all api route for Better Auth.

Terminal
mkdir -p src/routes/api/auth && touch src/routes/api/auth/$.ts
src/routes/api/auth/$.ts
import { createFileRoute } from "@tanstack/react-router";
import { auth } from "@/lib/auth";

export const Route = createFileRoute("/api/auth/$")({
	server: {
		handlers: {
			GET: async ({ request }: { request: Request }) => {
				return await auth.handler(request);
			},
			POST: async ({ request }: { request: Request }) => {
				return await auth.handler(request);
			},
		},
	},
});

Create Client Instance

Create a new file src/lib/auth-client.ts.

Terminal
touch src/lib/auth-client.ts`

```typescript:src/lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({})

Usage

src/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { tanstackStartCookies } from "better-auth/tanstack-start";
import { db } from "@/db";

export const auth = betterAuth({
	database: drizzleAdapter(db, {
		provider: "pg",
	}),
	emailAndPassword: {
		enabled: true,
	},
	plugins: [tanstackStartCookies()], // make sure this is the last plugin in the array
});

Git Commit

Terminal
git add .
git commit -am 'inital better auth setup'