Overview
This starter is set up for Google OAuth as the primary login, powered by Better Auth.
Optional: enable magic-link sign-in and email verification via Resend.
Key files:
- Better Auth server config:
tanstarter/src/auth.ts - Better Auth route handler:
tanstarter/src/routes/api/auth/$.ts - Client SDK:
tanstarter/src/lib/auth-client.ts - UI:
tanstarter/src/routes/login.tsx
Required env (minimum)
APP_URL=http://localhost:3000
VITE_APP_URL=http://localhost:3000
BETTER_AUTH_URL=http://localhost:3000
DATABASE_URL=postgresql://username:password@localhost:5432/database_name
BETTER_AUTH_SECRET=your-32-character-secret-here
Google OAuth (primary setup)
1) Create a Google Cloud project
- Open: Google Cloud Console
- Create a new project (or select an existing one).
2) Configure OAuth consent screen
- Go to APIs & Services → OAuth consent screen
- Choose External (most cases) or Internal (Google Workspace only)
- Fill out required fields (app name, support email, etc.)
- Add scopes (typical defaults are fine to start):
openidemailprofile
Google docs:
3) Create OAuth client credentials
- Go to APIs & Services → Credentials
- Click Create credentials → OAuth client ID
- Choose Web application
- Add the URLs below
Google docs:
4) Add authorized URLs (important)
In the OAuth client settings:
Authorized JavaScript origins
http://localhost:3000https://yourdomain.com
Authorized redirect URIs
http://localhost:3000/api/auth/callback/googlehttps://yourdomain.com/api/auth/callback/google
Why this path?
- Better Auth defaults to the
/api/authbase path on the server. - This repo wires the handler at
tanstarter/src/routes/api/auth/$.ts. - Better Auth’s callback route is
/api/auth/callback/:provider→ for Google that’s/api/auth/callback/google.
5) Set env vars and restart
Add to tanstarter/.env:
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
Restart bun run dev after env changes.
Resend (optional: magic links + verification emails)
If you want email-based auth flows:
- Create an account: Resend
- Add a domain and verify it
- Create an API key
- Set:
RESEND_API_KEY=re_your-resend-api-key
RESEND_FROM_ADDRESS="Your App <noreply@yourdomain.com>"
Resend docs:
Note: if RESEND_* is missing, Google OAuth still works; email flows will not send.
Checking auth on the server
Prefer Better Auth’s server API in server routes (example: tanstarter/src/routes/api/subscription.ts):
const session = await auth.api.getSession({ headers: request.headers })
if (!session?.user) return new Response('Unauthorized', { status: 401 })
Tables created by Better Auth
With the Drizzle adapter, Better Auth stores data in:
usersessionaccountverification