openAPI reference for the auth endpoints — without writing any auth
code yourself.
This page is a map of what’s already wired so you know what to touch and what to
leave alone. The provider-specific setup pages (Google OAuth, GitHub OAuth, One-Tap)
go deeper.
What’s wired
Look atsrc/lib/auth.ts — that’s the single source of truth. In short:
- Email + password with
minPasswordLength: 8andautoSignIn: trueafter registration. - Email verification sent on signup, link expires in 24 h, auto-signs in after verify.
- Reset password via emailed link, handled by
sendForgotPasswordEmailfromsrc/mail. - Social providers auto-enabled when their env vars are present (
GOOGLE_*,GITHUB_*). - Account linking on for trusted providers (
google,github) — same email lands on the same user. - Admin plugin with default role
userand admin roleadmin. - One-Tap plugin mounted when
siteConfig.features.enableOneTapandGOOGLE_CLIENT_IDare set. - openAPI plugin so you can browse the auth REST surface at
/api/auth/reference. - Delete user enabled — required for the GDPR data-deletion flow.
Prerequisites
- A Postgres database reachable via
DATABASE_URL. pnpm db:pushalready run (createsuser,session,account,verification).- A
BETTER_AUTH_SECRETof at least 16 characters (openssl rand -hex 32works). BETTER_AUTH_URLorNEXT_PUBLIC_APP_URLpointing at your site.- For email flows:
RESEND_API_KEY+ a verifiedRESEND_FROM_EMAIL.
Step-by-step setup
-
Generate a secret. Drop it into
.env.local: -
Push the schema. This creates the four Better Auth tables alongside vibestrap’s own.
-
Pick the auth methods you want. In
src/config/site.ts: - Wire the providers you turned on. Each has its own page:
-
(Optional) Promote yourself to admin. Add your email to
ADMIN_EMAILS(comma-separated) — the post-signup hook will setrole = 'admin'automatically:
The role system
Two roles only:user (default) and admin. The admin plugin handles the heavy
lifting; vibestrap adds one extra: a databaseHooks.user.create.after hook in
src/lib/auth.ts checks the new user’s email against ADMIN_EMAILS and promotes them.
Server actions can gate on role using the adminActionClient from
src/lib/safe-action.ts — see the admin pages under /admin for examples.
Session config
Defaults that ship insrc/lib/auth.ts:
| Setting | Value | Why |
|---|---|---|
expiresIn | 7 days | Shortish — re-auth catches stolen tokens. |
updateAge | 1 day | Slides the expiry forward on activity. |
cookieCache.maxAge | 1 hour | Avoids a DB lookup on every page load. |
cookieCache to a
shorter TTL or disable it.
Audit fields
Theuser schema has lastLoginAt, lastLoginIp, lastLoginUserAgent — populated
on every successful sign-in via Better Auth’s session hook. Useful for security
emails (“New sign-in from …”) and for the admin user list. Don’t query them on the
hot path; index them only if you actually run reports.
Verify it works
pnpm dev, visit/register, create an account.- Check the dev console — you should see the verification email logged by Resend.
- Click the verify link → you land on
/dashboardalready signed in. - Visit
/api/auth/referenceto browse the openAPI doc and confirm endpoints respond.
Common pitfalls
BETTER_AUTH_SECRETtoo short. Anything under 16 chars throws at startup.BETTER_AUTH_URLmismatch in prod. Cookies are scoped to this URL — get the scheme + host exactly right or sessions won’t stick.- Email verification stuck. Check that
RESEND_FROM_EMAIL’s domain is verified in Resend, otherwise the API silently drops the message. - Promoted admin doesn’t see admin UI. The hook only runs on signup. For an existing user, run an SQL update or re-create them.
- Schema drift after upgrading Better Auth. Re-run
pnpm db:push(dev) or generate a migration (prod).
Official docs
- Better Auth — better-auth.com/docs
- Admin plugin — better-auth.com/docs/plugins/admin
- One-Tap plugin — better-auth.com/docs/plugins/one-tap
- openAPI plugin — better-auth.com/docs/plugins/open-api