> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vibestrap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth overview

> How Vibestrap wires Better Auth — what's enabled, what plugins ship, and the role and session model.

Auth is the work every product needs and no product is differentiated by — yet a
homegrown setup typically eats 1-2 weeks of an indie launch and ships with at least
one subtle bug. vibestrap wires [Better Auth](https://www.better-auth.com) 1.4 in
completely: email + password, verification, forgot-password, change-password, Google

* GitHub OAuth, Google One-Tap, admin role, and an OpenAPI reference for every
  endpoint. You write zero auth code.

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`:

   ```bash theme={null}
   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.

   ```bash theme={null}
   pnpm db:push
   ```

3. **Pick the auth methods you want.** In `src/config/site.ts`:

   ```ts theme={null}
   features: {
     enableCredentialLogin: true,
     enableEmailVerification: true,
     enableGoogleLogin: true,
     enableGithubLogin: true,
     enableOneTap: true,
   }
   ```

4. **Wire the providers you turned on.** Each has its own page:
   * [Google OAuth](/auth/google-oauth)
   * [GitHub OAuth](/auth/github-oauth)
   * [One-Tap](/auth/one-tap)

5. **(Optional) Promote yourself to admin.** Add your email to `ADMIN_EMAILS`
   (comma-separated) — the post-signup hook will set `role = 'admin'` automatically:

   ```bash theme={null}
   ADMIN_EMAILS=you@example.com,cofounder@example.com
   ```

## 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`:

| 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.    |

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

* Better Auth — [better-auth.com/docs](https://www.better-auth.com/docs)
* Admin plugin — [better-auth.com/docs/plugins/admin](https://www.better-auth.com/docs/plugins/admin)
* One-Tap plugin — [better-auth.com/docs/plugins/one-tap](https://www.better-auth.com/docs/plugins/one-tap)
* openAPI plugin — [better-auth.com/docs/plugins/open-api](https://www.better-auth.com/docs/plugins/open-api)
