Ghost

struxadotcloud/struxa

public
Fork0
CodeIssues0Pull requests0
1branch
struxa.claudeskillsbetter-auth-best-practicesSKILL.md
feat: global unslop6531421a month ago183 lines · 6.7 KB
1---
2name: better-auth-best-practices
3description: Configure Better Auth server and client, set up database adapters, manage sessions, add plugins, and handle environment variables. Use when users mention Better Auth, betterauth, auth.ts, or need to set up TypeScript authentication with email/password, OAuth, or plugin configuration.
4---
5
6# Better Auth Integration Guide
7
8**Always consult [better-auth.com/docs
9
10---
11
12## Setup Workflow
13
141. Install: `npm install better-auth`
152. Set env vars: `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL`
163. Create `auth.ts` with database + config
174. Create route handler for your framework
185. Run `npx @better-auth/cli@latest migrate`
196. Verify: call `GET /api/auth/ok` - should return `{ status: "ok" }`
20
21---
22
23## Quick Reference
24
25### Environment Variables
26
27- `BETTER_AUTH_SECRET` - Encryption secret (min 32 chars). Generate: `openssl rand -base64 32`
28- `BETTER_AUTH_URL` - Base URL (e.g., `https://example.com`)
29
30Only define `baseURL`/`secret` in config if env vars are NOT set.
31
32### File Location
33
34CLI looks for `auth.ts` in: `./`, `
35
36### CLI Commands
37
38- `npx @better-auth/cli@latest migrate` - Apply schema (built-in adapter)
39- `npx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle
40- `npx @better-auth/cli mcp --cursor` - Add MCP to AI tools
41
42**Re-run after adding/changing plugins.**
43
44---
45
46## Core Config Options
47
48| Option | Notes |
49| ------------------ | ---------------------------------------------- |
50| `appName` | Optional display name |
51| `baseURL` | Only if `BETTER_AUTH_URL
52| `basePath` | Default `/api/auth
53| `secret` | Only if `BETTER_AUTH_SECRET
54| `database` | Required for most features. See adapters docs. |
55| `secondaryStorage` | Redis/KV for sessions & rate limits |
56| `emailAndPassword` | `{ enabled: true }
57| `socialProviders` | `{ google: { clientId, clientSecret }, ... }
58| `plugins` | Array of plugins |
59| `trustedOrigins` | CSRF whitelist |
60
61---
62
63## Database
64
65**Direct connections:** Pass `pg.Pool
66
67**ORM adapters:** Import from `better-auth/adapters/drizzle
68
69**Critical:** Better Auth uses adapter model names, NOT underlying table names. If Prisma model is `
70
71---
72
73## Session Management
74
75**Storage priority:**
76
771. If `secondaryStorage` defined → sessions go there (not DB)
782. Set `session.storeSessionInDatabase: true` to also persist to DB
793. No database + `cookieCache` → fully stateless mode
80
81**Cookie cache strategies:**
82
83- `compact` (default) - Base64url + HMAC. Smallest.
84- `jwt` - Standard JWT. Readable but signed.
85- `jwe` - Encrypted. Maximum security.
86
87**Key options:** `session.expiresIn
88
89---
90
91## User & Account Config
92
93**User:** `user.modelName
94
95**Account:** `account.modelName
96
97**Required for registration:** `email
98
99---
100
101## Email Flows
102
103- `emailVerification.sendVerificationEmail` - Must be defined for verification to work
104- `emailVerification.sendOnSignUp` / `sendOnSignIn` - Auto-send triggers
105- `emailAndPassword.sendResetPassword` - Password reset email handler
106
107---
108
109## Security
110
111**In `advanced
112
113- `useSecureCookies` - Force HTTPS cookies
114- `disableCSRFCheck` - ⚠️ Security risk
115- `disableOriginCheck` - ⚠️ Security risk
116- `crossSubDomainCookies.enabled` - Share cookies across subdomains
117- `ipAddress.ipAddressHeaders` - Custom IP headers for proxies
118- `database.generateId` - Custom ID generation or `"serial"`/
119
120**Rate limiting:** `rateLimit.enabled
121
122---
123
124## Hooks
125
126**Endpoint hooks:** `hooks.before
127
128**Database hooks:** `databaseHooks.user.create.before/after
129
130**Hook context (`ctx.context
131
132---
133
134## Plugins
135
136**Import from dedicated paths for tree-shaking:**
137
138```
139import { twoFactor } from "better-auth/plugins/two-factor"
140```
141
142NOT `from "better-auth/plugins"`.
143
144**Popular plugins:** `twoFactor
145
146Client plugins go in `createAuthClient({ plugins: [...] })`.
147
148---
149
150## Client
151
152Import from: `better-auth/client` (vanilla), `better-auth/react`, `
153
154Key methods: `signUp.email()`, `signIn.email()`, `
155
156---
157
158## Type Safety
159
160Infer types: `typeof auth.$Infer.Session`, `typeof auth.$Infer.Session.user`.
161
162For separate client/server projects: `createAuthClient<typeof auth>()`.
163
164---
165
166## Common Gotchas
167
1681. **Model vs table name** - Config uses ORM model name, not DB table name
1692. **Plugin schema** - Re-run CLI after adding plugins
1703. **Secondary storage** - Sessions go there by default, not DB
1714. **Cookie cache** - Custom session fields NOT cached, always re-fetched
1725. **Stateless mode** - No DB = session in cookie only, logout on cache expiry
1736. **Change email flow** - Sends to current email first, then new email
174
175---
176
177## Resources
178
179- [Docs](https://better-auth.com/docs
180- [Options Reference](https://better-auth.com/docs/reference/options
181- [LLMs.txt](https://better-auth.com/llms.txt
182- [GitHub](https://github.com/better-auth/better-auth
183- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts
]
(
https://better-auth.com/docs
)
for code examples and latest API.
**
./lib
`
,
`
./utils
`
, or under
`
./src
`
. Use
`
--config
`
for custom path.
`
not set
|
`
. Set
`
/
`
for root.
|
`
not set
|
`
to activate
|
`
|
`
,
`
mysql2
`
pool,
`
better-sqlite3
`
, or
`
bun:sqlite
`
instance.
`
,
`
better-auth/adapters/prisma
`
,
`
better-auth/adapters/mongodb
`
.
User
`
mapping to table
`
users
`
, use
`
modelName: "user"
`
(Prisma reference), not
`
"users"
`
.
`
(default 7 days),
`
session.updateAge
`
(refresh interval),
`
session.cookieCache.maxAge
`
,
`
session.cookieCache.version
`
(change to invalidate all sessions).
`
,
`
user.fields
`
(column mapping),
`
user.additionalFields
`
,
`
user.changeEmail.enabled
`
(disabled by default),
`
user.deleteUser.enabled
`
(disabled by default).
`
,
`
account.accountLinking.enabled
`
,
`
account.storeAccountCookie
`
(for stateless OAuth).
`
and
`
name
`
fields.
`
:
**
`
"uuid"
`
/
`
false
`
`
,
`
rateLimit.window
`
,
`
rateLimit.max
`
,
`
rateLimit.storage
`
("memory" | "database" | "secondary-storage").
`
/
`
hooks.after
`
- Array of
`
{ matcher, handler }
`
. Use
`
createAuthMiddleware
`
. Access
`
ctx.path
`
,
`
ctx.context.returned
`
(after),
`
ctx.context.session
`
.
`
, same for
`
session
`
,
`
account
`
. Useful for adding default values or post-creation actions.
`
):
**
`
session
`
,
`
secret
`
,
`
authCookies
`
,
`
password.hash()
`
/
`
verify()
`
,
`
adapter
`
,
`
internalAdapter
`
,
`
generateId()
`
,
`
tables
`
,
`
baseURL
`
.
`
,
`
organization
`
,
`
passkey
`
,
`
magicLink
`
,
`
emailOtp
`
,
`
username
`
,
`
phoneNumber
`
,
`
admin
`
,
`
apiKey
`
,
`
bearer
`
,
`
jwt
`
,
`
multiSession
`
,
`
sso
`
,
`
oauthProvider
`
,
`
oidcProvider
`
,
`
openAPI
`
,
`
genericOAuth
`
.
better-auth/vue
`
,
`
better-auth/svelte
`
,
`
better-auth/solid
`
.
signIn.social()
`
,
`
signOut()
`
,
`
useSession()
`
,
`
getSession()
`
,
`
revokeSession()
`
,
`
revokeSessions()
`
.
)
)
)
)
)