Skip to main content
vibestrap ships with Better Auth 1.4 wired into the Postgres schema and React client. You get email + password, email verification, forgot-password, change-password, Google + GitHub OAuth, Google One-Tap, an admin role, and an 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 at src/lib/auth.ts — that’s the single source of truth. In short:
  • Email + password with minPasswordLength: 8 and autoSignIn: true after registration.
  • Email verification sent on signup, link expires in 24 h, auto-signs in after verify.
  • Reset password via emailed link, handled by sendForgotPasswordEmail from src/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 user and admin role admin.
  • One-Tap plugin mounted when siteConfig.features.enableOneTap and GOOGLE_CLIENT_ID are 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:push already run (creates user, session, account, verification).
  • A BETTER_AUTH_SECRET of at least 16 characters (openssl rand -hex 32 works).
  • BETTER_AUTH_URL or NEXT_PUBLIC_APP_URL pointing at your site.
  • For email flows: RESEND_API_KEY + a verified RESEND_FROM_EMAIL.

Step-by-step setup

  1. Generate a secret. Drop it into .env.local:
    BETTER_AUTH_SECRET=$(openssl rand -hex 32)
    BETTER_AUTH_URL=http://localhost:3000
    
  2. Push the schema. This creates the four Better Auth tables alongside vibestrap’s own.
    pnpm db:push
    
  3. Pick the auth methods you want. In src/config/site.ts:
    features: {
      enableCredentialLogin: true,
      enableEmailVerification: true,
      enableGoogleLogin: true,
      enableGithubLogin: true,
      enableOneTap: true,
    }
    
  4. Wire the providers you turned on. Each has its own page:
  5. (Optional) Promote yourself to admin. Add your email to ADMIN_EMAILS (comma-separated) — the post-signup hook will set role = '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 in src/lib/auth.ts:
SettingValueWhy
expiresIn7 daysShortish — re-auth catches stolen tokens.
updateAge1 daySlides the expiry forward on activity.
cookieCache.maxAge1 hourAvoids a DB lookup on every page load.
Cookie-cache means a recently-revoked session can still feel valid for up to an hour. If you need instant revocation (think enterprise) drop cookieCache to a shorter TTL or disable it.

Audit fields

The user 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

  1. pnpm dev, visit /register, create an account.
  2. Check the dev console — you should see the verification email logged by Resend.
  3. Click the verify link → you land on /dashboard already signed in.
  4. Visit /api/auth/reference to browse the openAPI doc and confirm endpoints respond.

Common pitfalls

  • BETTER_AUTH_SECRET too short. Anything under 16 chars throws at startup.
  • BETTER_AUTH_URL mismatch 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