---
title: "Better Auth"
description: "Use Better Auth, an open-source library in your app, for MainSDK auth - database, secret, main.yaml, local testing and swapping."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/better-auth"
updated: "2026-10-28"
---

# Better Auth

> Use Better Auth, an open-source library in your app, for MainSDK auth - database, secret, main.yaml, local testing and swapping.

Canonical: https://mainsdk.dev/docs/integrations/better-auth · Updated: 2026-10-28

Better Auth is an open-source TypeScript authentication library that runs inside your app and keeps users in your own database. Behind [`auth`](https://mainsdk.dev/docs/interfaces/auth), it gives you sign-in with no hosted identity service to sign up for. Pick it when you want users in your own Postgres and no third-party user directory. The `auth` spec proposes Better Auth and Clerk as the two drivers that make `auth` stable in 0.3.

## Interfaces it serves

### Sign-in and sessions (`auth`)

- Status: Building for 0.3 · ships as a stable API
- Driver: `better-auth` (Better Auth)
- Docs: https://mainsdk.dev/docs/interfaces/auth.md

```yaml
auth:
  driver: better-auth
```

Swap to another provider: `github`, `clerk`, `auth0`, `workos`, `supabase`, `local`.

## Before you start

There is no account to create; you run Better Auth yourself.

1. **Pick the database** that holds users and sessions, such as your Postgres, and apply Better Auth's schema to it.
2. **Generate a long random secret** that Better Auth uses to sign and encrypt its tokens, one per environment.
3. **Register any social providers** you offer, such as a GitHub OAuth app, and keep their client secrets.

## Configure

```yaml title="main.yaml"
auth:
  driver: better-auth
  methods: [passkeys]
  # [TBD] key names; suggested secrets: BETTER_AUTH_SECRET and the users database connection
```

The `auth` spec does not define the driver's credential keys yet; they take `secret:` references when it does.

## Use it

```ts title="app/api/me/route.ts"
import { auth } from "mainsdk";

export async function GET(req: Request) {
  const session = await auth.require(req);   // 401 with MAIN-AUTH-0001 if not signed in
  return Response.json(session.user);
}
```

## Local development and testing

Use the `local` auth driver in development, or run Better Auth against a local database. In tests, `createTestApp()` from `@mainsdk/testing` puts `auth` on its in-memory fake, and `chaos.on("auth", { outage: true })` checks that `auth.require()` fails closed.

## What MainSDK adds on top

- Short-lived, HttpOnly, Secure, SameSite sessions with rotating refresh tokens.
- Passkeys by default, phishing-resistant.
- Fails closed when the driver cannot reach its store.
- Every recovery audited, never weaker than sign-in.

See [Sign-in and sessions](https://mainsdk.dev/docs/interfaces/auth).

## Limits and notes

- Users live in your database, so their residency follows where you host it; MainSDK's regions are US, EU and India.
- The Better Auth driver is in the `auth` spec's first driver ticket with Clerk, held to the auth conformance suite.
- `auth.raw()` returns the library's instance for features `auth` does not wrap; `mainsdk check` lists every use.

## Swap to or from it

```yaml title="main.yaml"
auth:
  driver: clerk   # was better-auth
```

> **Warning:** Your users and sessions live in your database. Moving them to a hosted provider is a migration that MainSDK runs as a guided job with a rollback, not a silent switch.

## FAQ

**Do I need a Better Auth account?** No. It is a library; you need a database and a secret.

**Can I keep my existing Better Auth setup?** Yes. The driver runs on your existing tables (`byo-identity`).

## Next

- [Sign-in and sessions](https://mainsdk.dev/docs/interfaces/auth)
- [Clerk](https://mainsdk.dev/docs/integrations/clerk), [GitHub](https://mainsdk.dev/docs/integrations/github) and [Postgres](https://mainsdk.dev/docs/integrations/postgres)
- [Swap a driver](https://mainsdk.dev/docs/guides/swap-a-driver)
