@onmax/nuxt-better-auth 0.0.2-alpha.12 → 0.0.2-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +49 -162
- package/dist/runtime/server/api/_better-auth/config.get.js +2 -2
- package/dist/runtime/server/api/auth/[...all].js +1 -1
- package/dist/runtime/server/utils/auth.d.ts +3 -1
- package/dist/runtime/server/utils/auth.js +61 -4
- package/dist/runtime/server/utils/session.js +1 -1
- package/package.json +14 -6
- package/skills/nuxt-better-auth/SKILL.md +92 -0
- package/skills/nuxt-better-auth/references/client-auth.md +153 -0
- package/skills/nuxt-better-auth/references/client-only.md +89 -0
- package/skills/nuxt-better-auth/references/database.md +115 -0
- package/skills/nuxt-better-auth/references/installation.md +126 -0
- package/skills/nuxt-better-auth/references/plugins.md +138 -0
- package/skills/nuxt-better-auth/references/route-protection.md +105 -0
- package/skills/nuxt-better-auth/references/server-auth.md +135 -0
- package/skills/nuxt-better-auth/references/types.md +142 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Client-Side Authentication
|
|
2
|
+
|
|
3
|
+
## useUserSession()
|
|
4
|
+
|
|
5
|
+
Main composable for auth state and methods.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const {
|
|
9
|
+
user, // Ref<AuthUser | null>
|
|
10
|
+
session, // Ref<AuthSession | null>
|
|
11
|
+
loggedIn, // ComputedRef<boolean>
|
|
12
|
+
ready, // ComputedRef<boolean> - session fetch complete
|
|
13
|
+
client, // Better Auth client (client-side only)
|
|
14
|
+
signIn, // Proxy to client.signIn
|
|
15
|
+
signUp, // Proxy to client.signUp
|
|
16
|
+
signOut, // Sign out and clear session
|
|
17
|
+
fetchSession, // Manually refresh session
|
|
18
|
+
updateUser // Optimistic local user update
|
|
19
|
+
} = useUserSession()
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Sign In
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// Email/password
|
|
26
|
+
await signIn.email({
|
|
27
|
+
email: 'user@example.com',
|
|
28
|
+
password: 'password123'
|
|
29
|
+
}, {
|
|
30
|
+
onSuccess: () => navigateTo('/dashboard')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// OAuth
|
|
34
|
+
await signIn.social({ provider: 'github' })
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Sign Up
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await signUp.email({
|
|
41
|
+
email: 'user@example.com',
|
|
42
|
+
password: 'password123',
|
|
43
|
+
name: 'John Doe'
|
|
44
|
+
}, {
|
|
45
|
+
onSuccess: () => navigateTo('/welcome')
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Sign Out
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
await signOut()
|
|
53
|
+
// or with redirect
|
|
54
|
+
await signOut({ redirect: '/login' })
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Check Auth State
|
|
58
|
+
|
|
59
|
+
```vue
|
|
60
|
+
<script setup>
|
|
61
|
+
const { user, loggedIn, ready } = useUserSession()
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<template>
|
|
65
|
+
<div v-if="!ready">Loading...</div>
|
|
66
|
+
<div v-else-if="loggedIn">Welcome, {{ user?.name }}</div>
|
|
67
|
+
<div v-else>Please log in</div>
|
|
68
|
+
</template>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Safe Redirects
|
|
72
|
+
|
|
73
|
+
Always validate redirect URLs from query params to prevent open redirects:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
function getSafeRedirect() {
|
|
77
|
+
const redirect = route.query.redirect as string
|
|
78
|
+
// Must start with / and not // (prevents protocol-relative URLs)
|
|
79
|
+
if (!redirect?.startsWith('/') || redirect.startsWith('//')) {
|
|
80
|
+
return '/'
|
|
81
|
+
}
|
|
82
|
+
return redirect
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await signIn.email({
|
|
86
|
+
email, password
|
|
87
|
+
}, {
|
|
88
|
+
onSuccess: () => navigateTo(getSafeRedirect())
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Wait for Session
|
|
93
|
+
|
|
94
|
+
Useful when needing session before rendering:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
await waitForSession() // 5s timeout
|
|
98
|
+
if (loggedIn.value) {
|
|
99
|
+
// Session is ready
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Manual Session Refresh
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// Refetch from server
|
|
107
|
+
await fetchSession({ force: true })
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Session Management
|
|
111
|
+
|
|
112
|
+
Additional session management via Better Auth client:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const { client } = useUserSession()
|
|
116
|
+
|
|
117
|
+
// List all active sessions for current user
|
|
118
|
+
const sessions = await client.listSessions()
|
|
119
|
+
|
|
120
|
+
// Revoke a specific session
|
|
121
|
+
await client.revokeSession({ sessionId: 'xxx' })
|
|
122
|
+
|
|
123
|
+
// Revoke all sessions except current
|
|
124
|
+
await client.revokeOtherSessions()
|
|
125
|
+
|
|
126
|
+
// Revoke all sessions (logs out everywhere)
|
|
127
|
+
await client.revokeSessions()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
These methods require the user to be authenticated.
|
|
131
|
+
|
|
132
|
+
## BetterAuthState Component
|
|
133
|
+
|
|
134
|
+
Renders once session hydration completes (`ready === true`), with loading placeholder support.
|
|
135
|
+
|
|
136
|
+
```vue
|
|
137
|
+
<BetterAuthState>
|
|
138
|
+
<template #default="{ loggedIn, user, session, signOut }">
|
|
139
|
+
<p v-if="loggedIn">Hi {{ user?.name }}</p>
|
|
140
|
+
<button v-else @click="navigateTo('/login')">Sign in</button>
|
|
141
|
+
</template>
|
|
142
|
+
<template #placeholder>
|
|
143
|
+
<p>Loading…</p>
|
|
144
|
+
</template>
|
|
145
|
+
</BetterAuthState>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Slots:**
|
|
149
|
+
|
|
150
|
+
- `default` - Renders when `ready === true`, provides `{ loggedIn, user, session, signOut }`
|
|
151
|
+
- `placeholder` - Renders while session hydrates
|
|
152
|
+
|
|
153
|
+
Useful in clientOnly mode or for graceful SSR loading states.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Client-Only Mode (External Auth Backend)
|
|
2
|
+
|
|
3
|
+
When Better Auth runs on a separate backend (microservices, standalone server), use `clientOnly` mode.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
### 1. Enable in nuxt.config.ts
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export default defineNuxtConfig({
|
|
11
|
+
modules: ['@onmax/nuxt-better-auth'],
|
|
12
|
+
auth: {
|
|
13
|
+
clientOnly: true,
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Point client to external server
|
|
19
|
+
|
|
20
|
+
```ts [app/auth.config.ts]
|
|
21
|
+
import { createAuthClient } from 'better-auth/vue'
|
|
22
|
+
|
|
23
|
+
export function createAppAuthClient(_baseURL: string) {
|
|
24
|
+
return createAuthClient({
|
|
25
|
+
baseURL: 'https://auth.example.com', // External auth server
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 3. Set frontend URL
|
|
31
|
+
|
|
32
|
+
```ini [.env]
|
|
33
|
+
NUXT_PUBLIC_SITE_URL="https://your-frontend.com"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## What Changes
|
|
37
|
+
|
|
38
|
+
| Feature | Full Mode | Client-Only |
|
|
39
|
+
| ----------------------------------------------------------------------------- | --------------- | ----------------- |
|
|
40
|
+
| `server/auth.config.ts` | Required | Not needed |
|
|
41
|
+
| `/api/auth/**` handlers | Auto-registered | Skipped |
|
|
42
|
+
| `NUXT_BETTER_AUTH_SECRET` | Required | Not needed |
|
|
43
|
+
| Server utilities (`serverAuth()`, `getUserSession()`, `requireUserSession()`) | Available | **Not available** |
|
|
44
|
+
| SSR session hydration | Server-side | Client-side only |
|
|
45
|
+
| `useUserSession()`, route protection, `<BetterAuthState>` | Works | Works |
|
|
46
|
+
|
|
47
|
+
## CORS Requirements
|
|
48
|
+
|
|
49
|
+
Ensure external auth server:
|
|
50
|
+
|
|
51
|
+
- Allows requests from frontend (CORS with `credentials: true`)
|
|
52
|
+
- Uses `SameSite=None; Secure` cookies (HTTPS required)
|
|
53
|
+
- Includes frontend URL in `trustedOrigins`
|
|
54
|
+
|
|
55
|
+
## SSR Considerations
|
|
56
|
+
|
|
57
|
+
Session fetched client-side only:
|
|
58
|
+
|
|
59
|
+
- Server-rendered pages render as "unauthenticated" initially
|
|
60
|
+
- Hydrates with session data on client
|
|
61
|
+
- Use `<BetterAuthState>` for loading states
|
|
62
|
+
|
|
63
|
+
```vue
|
|
64
|
+
<BetterAuthState v-slot="{ isLoading, user }">
|
|
65
|
+
<div v-if="isLoading">Loading...</div>
|
|
66
|
+
<div v-else-if="user">Welcome, {{ user.name }}</div>
|
|
67
|
+
<div v-else>Please log in</div>
|
|
68
|
+
</BetterAuthState>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Use Cases
|
|
72
|
+
|
|
73
|
+
- **Microservices**: Auth service is separate deployment
|
|
74
|
+
- **Shared auth**: Multiple frontends share one auth backend
|
|
75
|
+
- **Existing backend**: Already have Better Auth server running elsewhere
|
|
76
|
+
|
|
77
|
+
## Architecture Example
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
81
|
+
│ Nuxt App │────▶│ Auth Server │
|
|
82
|
+
│ (clientOnly) │ │ (Better Auth) │
|
|
83
|
+
│ │◀────│ │
|
|
84
|
+
└─────────────────┘ └────────┬────────┘
|
|
85
|
+
│
|
|
86
|
+
┌────────▼────────┐
|
|
87
|
+
│ Database │
|
|
88
|
+
└─────────────────┘
|
|
89
|
+
```
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Database Integration
|
|
2
|
+
|
|
3
|
+
## NuxtHub Setup
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
// nuxt.config.ts
|
|
7
|
+
export default defineNuxtConfig({
|
|
8
|
+
modules: ['@nuxthub/core', '@onmax/nuxt-better-auth'],
|
|
9
|
+
hub: { database: true },
|
|
10
|
+
auth: {
|
|
11
|
+
secondaryStorage: true, // Optional: KV for session caching
|
|
12
|
+
schema: {
|
|
13
|
+
usePlural: false, // user vs users
|
|
14
|
+
casing: 'camelCase' // camelCase or snake_case
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Schema Generation
|
|
21
|
+
|
|
22
|
+
The module auto-generates Drizzle schema from Better Auth tables. Schema available via:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { user, session, account, verification } from '#auth/database'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Database Dialect
|
|
29
|
+
|
|
30
|
+
Supports: `sqlite`, `postgresql`, `mysql`
|
|
31
|
+
|
|
32
|
+
Schema syntax adapts to dialect:
|
|
33
|
+
|
|
34
|
+
- SQLite: `integer('id').primaryKey()`
|
|
35
|
+
- PostgreSQL/MySQL: `uuid('id').primaryKey()` or `text('id').primaryKey()`
|
|
36
|
+
|
|
37
|
+
## Schema Options
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
auth: {
|
|
41
|
+
schema: {
|
|
42
|
+
usePlural: true, // tables: users, sessions, accounts
|
|
43
|
+
casing: 'snake_case' // columns: created_at, updated_at
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| Option | Default | Description |
|
|
49
|
+
| ----------- | ------------- | ------------------------ |
|
|
50
|
+
| `usePlural` | `false` | Pluralize table names |
|
|
51
|
+
| `casing` | `'camelCase'` | Column naming convention |
|
|
52
|
+
|
|
53
|
+
## Extending Schema
|
|
54
|
+
|
|
55
|
+
Add custom columns via NuxtHub's schema hooks:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// server/plugins/extend-schema.ts
|
|
59
|
+
export default defineNitroPlugin(() => {
|
|
60
|
+
useNitroApp().hooks.hook('hub:db:schema:extend', (schema) => {
|
|
61
|
+
// Add custom tables or extend existing
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Secondary Storage (KV)
|
|
67
|
+
|
|
68
|
+
Enable session caching with KV:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
auth: {
|
|
72
|
+
secondaryStorage: true
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Requires `hub.kv: true` in config. Improves session lookup performance.
|
|
77
|
+
|
|
78
|
+
## Server Config with DB
|
|
79
|
+
|
|
80
|
+
Database adapter injected via context:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// server/auth.config.ts
|
|
84
|
+
import { defineServerAuth } from '#auth/server'
|
|
85
|
+
|
|
86
|
+
export default defineServerAuth(({ db }) => ({
|
|
87
|
+
database: db, // Already configured when hub.database: true
|
|
88
|
+
emailAndPassword: { enabled: true }
|
|
89
|
+
}))
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Manual Database Setup
|
|
93
|
+
|
|
94
|
+
Without NuxtHub, configure manually:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// server/auth.config.ts
|
|
98
|
+
import { drizzle } from 'drizzle-orm/...'
|
|
99
|
+
import { defineServerAuth } from '#auth/server'
|
|
100
|
+
|
|
101
|
+
const db = drizzle(...)
|
|
102
|
+
|
|
103
|
+
export default defineServerAuth(() => ({
|
|
104
|
+
database: drizzleAdapter(db, { provider: 'sqlite' })
|
|
105
|
+
}))
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Migrations
|
|
109
|
+
|
|
110
|
+
Better Auth creates tables automatically on first run. For production, generate migrations:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Using Better Auth CLI
|
|
114
|
+
npx better-auth generate
|
|
115
|
+
```
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Installation & Configuration
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pnpm add @onmax/nuxt-better-auth better-auth
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
**Version Requirements:**
|
|
10
|
+
|
|
11
|
+
- `@onmax/nuxt-better-auth`: `^0.0.2-alpha.12` (alpha)
|
|
12
|
+
- `better-auth`: `^1.0.0` (module tested with `1.4.7`)
|
|
13
|
+
- `@nuxthub/core`: `^0.10.0` (optional, for database)
|
|
14
|
+
|
|
15
|
+
## Module Setup
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// nuxt.config.ts
|
|
19
|
+
export default defineNuxtConfig({
|
|
20
|
+
modules: ['@onmax/nuxt-better-auth'],
|
|
21
|
+
auth: {
|
|
22
|
+
serverConfig: 'server/auth.config', // default
|
|
23
|
+
clientConfig: 'app/auth.config', // default
|
|
24
|
+
clientOnly: false, // true for external auth backend
|
|
25
|
+
redirects: {
|
|
26
|
+
login: '/login', // redirect when auth required
|
|
27
|
+
guest: '/' // redirect when already logged in
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Environment Variables
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Required (min 32 chars)
|
|
37
|
+
BETTER_AUTH_SECRET=your-secret-key-at-least-32-characters
|
|
38
|
+
|
|
39
|
+
# Required in production for OAuth
|
|
40
|
+
NUXT_PUBLIC_SITE_URL=https://your-domain.com
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Server Config
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// server/auth.config.ts
|
|
47
|
+
import { defineServerAuth } from '#auth/server'
|
|
48
|
+
|
|
49
|
+
export default defineServerAuth(({ runtimeConfig, db }) => ({
|
|
50
|
+
emailAndPassword: { enabled: true },
|
|
51
|
+
// OAuth providers
|
|
52
|
+
socialProviders: {
|
|
53
|
+
github: {
|
|
54
|
+
clientId: runtimeConfig.github.clientId,
|
|
55
|
+
clientSecret: runtimeConfig.github.clientSecret
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
// Session configuration (optional)
|
|
59
|
+
session: {
|
|
60
|
+
expiresIn: 60 * 60 * 24 * 7, // 7 days (default)
|
|
61
|
+
updateAge: 60 * 60 * 24, // Update every 24h (default)
|
|
62
|
+
freshAge: 60 * 60 * 24, // Consider fresh for 24h (default, 0 to disable)
|
|
63
|
+
cookieCache: {
|
|
64
|
+
enabled: true,
|
|
65
|
+
maxAge: 60 * 5 // 5 minutes cookie cache
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}))
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Context available in `defineServerAuth`:
|
|
72
|
+
|
|
73
|
+
- `runtimeConfig` - Nuxt runtime config
|
|
74
|
+
- `db` - Database adapter (when NuxtHub enabled)
|
|
75
|
+
|
|
76
|
+
### Session Options
|
|
77
|
+
|
|
78
|
+
| Option | Default | Description |
|
|
79
|
+
| ----------------------- | ------------------ | --------------------------------------------- |
|
|
80
|
+
| `expiresIn` | `604800` (7 days) | Session lifetime in seconds |
|
|
81
|
+
| `updateAge` | `86400` (24 hours) | How often to refresh session expiry |
|
|
82
|
+
| `freshAge` | `86400` (24 hours) | Session considered "fresh" period (0 = never) |
|
|
83
|
+
| `cookieCache.enabled` | `false` | Enable cookie caching to reduce DB queries |
|
|
84
|
+
| `cookieCache.maxAge` | `300` (5 minutes) | Cookie cache lifetime |
|
|
85
|
+
| `disableSessionRefresh` | `false` | Disable automatic session refresh |
|
|
86
|
+
|
|
87
|
+
## Client Config
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// app/auth.config.ts
|
|
91
|
+
import { createAppAuthClient } from '#auth/client'
|
|
92
|
+
|
|
93
|
+
export default createAppAuthClient({
|
|
94
|
+
// Client-side plugin options (e.g., passkey, twoFactor)
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## NuxtHub Integration
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// nuxt.config.ts
|
|
102
|
+
export default defineNuxtConfig({
|
|
103
|
+
modules: ['@nuxthub/core', '@onmax/nuxt-better-auth'],
|
|
104
|
+
hub: { database: true },
|
|
105
|
+
auth: {
|
|
106
|
+
secondaryStorage: true // Enable KV for session caching
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See [references/database.md](database.md) for schema setup.
|
|
112
|
+
|
|
113
|
+
## Client-Only Mode
|
|
114
|
+
|
|
115
|
+
For external auth backends (microservices, separate servers):
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// nuxt.config.ts
|
|
119
|
+
export default defineNuxtConfig({
|
|
120
|
+
auth: {
|
|
121
|
+
clientOnly: true, // No local auth server
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
See [references/client-only.md](client-only.md) for full setup.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Better Auth Plugins
|
|
2
|
+
|
|
3
|
+
The module supports all Better Auth plugins. Configure in both server and client configs.
|
|
4
|
+
|
|
5
|
+
## Server Plugin Setup
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// server/auth.config.ts
|
|
9
|
+
import { defineServerAuth } from '#auth/server'
|
|
10
|
+
|
|
11
|
+
export default defineServerAuth(({ runtimeConfig }) => ({
|
|
12
|
+
emailAndPassword: { enabled: true },
|
|
13
|
+
plugins: [
|
|
14
|
+
admin(),
|
|
15
|
+
twoFactor({ issuer: 'MyApp' }),
|
|
16
|
+
passkey(),
|
|
17
|
+
multiSession()
|
|
18
|
+
]
|
|
19
|
+
}))
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Client Plugin Setup
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// app/auth.config.ts
|
|
26
|
+
import { createAppAuthClient } from '#auth/client'
|
|
27
|
+
import { adminClient, twoFactorClient, passkeyClient, multiSessionClient } from 'better-auth/client/plugins'
|
|
28
|
+
|
|
29
|
+
export default createAppAuthClient({
|
|
30
|
+
plugins: [
|
|
31
|
+
adminClient(),
|
|
32
|
+
twoFactorClient(),
|
|
33
|
+
passkeyClient(),
|
|
34
|
+
multiSessionClient()
|
|
35
|
+
]
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Common Plugins
|
|
40
|
+
|
|
41
|
+
### Admin
|
|
42
|
+
|
|
43
|
+
Role-based access control:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// Server
|
|
47
|
+
import { admin } from 'better-auth/plugins'
|
|
48
|
+
plugins: [admin()]
|
|
49
|
+
|
|
50
|
+
// Client
|
|
51
|
+
import { adminClient } from 'better-auth/client/plugins'
|
|
52
|
+
plugins: [adminClient()]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Usage:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// Protect route
|
|
59
|
+
await requireUserSession(event, { user: { role: 'admin' } })
|
|
60
|
+
|
|
61
|
+
// Client: set user role
|
|
62
|
+
await client.admin.setRole({ userId: 'xxx', role: 'admin' })
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Two-Factor (2FA)
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// Server
|
|
69
|
+
import { twoFactor } from 'better-auth/plugins'
|
|
70
|
+
plugins: [twoFactor({ issuer: 'MyApp' })]
|
|
71
|
+
|
|
72
|
+
// Client
|
|
73
|
+
import { twoFactorClient } from 'better-auth/client/plugins'
|
|
74
|
+
plugins: [twoFactorClient()]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Usage:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// Enable 2FA
|
|
81
|
+
const { totpURI } = await client.twoFactor.enable({ password: 'xxx' })
|
|
82
|
+
// Show QR code with totpURI
|
|
83
|
+
|
|
84
|
+
// Verify OTP on login
|
|
85
|
+
await client.twoFactor.verifyTotp({ code: '123456' })
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Passkey
|
|
89
|
+
|
|
90
|
+
WebAuthn/FIDO2 authentication:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
// Server
|
|
94
|
+
import { passkey } from 'better-auth/plugins'
|
|
95
|
+
plugins: [passkey()]
|
|
96
|
+
|
|
97
|
+
// Client
|
|
98
|
+
import { passkeyClient } from 'better-auth/client/plugins'
|
|
99
|
+
plugins: [passkeyClient()]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Usage:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
// Register passkey
|
|
106
|
+
await client.passkey.addPasskey()
|
|
107
|
+
|
|
108
|
+
// Sign in with passkey
|
|
109
|
+
await signIn.passkey()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Multi-Session
|
|
113
|
+
|
|
114
|
+
Allow multiple concurrent sessions:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// Server
|
|
118
|
+
import { multiSession } from 'better-auth/plugins'
|
|
119
|
+
plugins: [multiSession()]
|
|
120
|
+
|
|
121
|
+
// Client
|
|
122
|
+
import { multiSessionClient } from 'better-auth/client/plugins'
|
|
123
|
+
plugins: [multiSessionClient()]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Usage:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// List all sessions
|
|
130
|
+
const sessions = await client.multiSession.listDeviceSessions()
|
|
131
|
+
|
|
132
|
+
// Revoke specific session
|
|
133
|
+
await client.multiSession.revokeSession({ sessionId: 'xxx' })
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Plugin Type Inference
|
|
137
|
+
|
|
138
|
+
Types from plugins are automatically inferred. See [references/types.md](types.md) for type augmentation.
|