@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,105 @@
|
|
|
1
|
+
# Route Protection
|
|
2
|
+
|
|
3
|
+
Three layers of protection: route rules, page meta, and server middleware.
|
|
4
|
+
|
|
5
|
+
## Route Rules (Global)
|
|
6
|
+
|
|
7
|
+
Define auth requirements in `nuxt.config.ts`:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export default defineNuxtConfig({
|
|
11
|
+
routeRules: {
|
|
12
|
+
'/admin/**': { auth: { user: { role: 'admin' } } },
|
|
13
|
+
'/dashboard/**': { auth: 'user' },
|
|
14
|
+
'/login': { auth: 'guest' },
|
|
15
|
+
'/public/**': { auth: false }
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Auth Modes
|
|
21
|
+
|
|
22
|
+
| Mode | Behavior |
|
|
23
|
+
| ----------------- | ------------------------------------------------------ |
|
|
24
|
+
| `'user'` | Requires authenticated user |
|
|
25
|
+
| `'guest'` | Only unauthenticated users (redirects logged-in users) |
|
|
26
|
+
| `{ user: {...} }` | Requires user matching specific properties |
|
|
27
|
+
| `false` | No protection |
|
|
28
|
+
|
|
29
|
+
## Page Meta (Per-Page)
|
|
30
|
+
|
|
31
|
+
Override or define auth for specific pages:
|
|
32
|
+
|
|
33
|
+
```vue
|
|
34
|
+
<script setup>
|
|
35
|
+
// Require authentication
|
|
36
|
+
definePageMeta({ auth: 'user' })
|
|
37
|
+
</script>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<script setup>
|
|
42
|
+
// Require admin role
|
|
43
|
+
definePageMeta({
|
|
44
|
+
auth: { user: { role: 'admin' } }
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<script setup>
|
|
51
|
+
// Guest-only (login page)
|
|
52
|
+
definePageMeta({ auth: 'guest' })
|
|
53
|
+
</script>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## User Property Matching
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// Single value
|
|
60
|
+
{ auth: { user: { role: 'admin' } } }
|
|
61
|
+
|
|
62
|
+
// OR logic (array)
|
|
63
|
+
{ auth: { user: { role: ['admin', 'moderator'] } } }
|
|
64
|
+
|
|
65
|
+
// AND logic (multiple fields)
|
|
66
|
+
{ auth: { user: { role: 'admin', verified: true } } }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Redirect Configuration
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// nuxt.config.ts
|
|
73
|
+
export default defineNuxtConfig({
|
|
74
|
+
auth: {
|
|
75
|
+
redirects: {
|
|
76
|
+
login: '/login', // Where to redirect unauthenticated users
|
|
77
|
+
guest: '/dashboard' // Where to redirect logged-in users from guest pages
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Server Middleware
|
|
84
|
+
|
|
85
|
+
Auth middleware runs on all `/api/**` routes matching `routeRules`.
|
|
86
|
+
|
|
87
|
+
For custom API protection, use `requireUserSession()`:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// server/api/admin/[...].ts
|
|
91
|
+
export default defineEventHandler(async (event) => {
|
|
92
|
+
await requireUserSession(event, { user: { role: 'admin' } })
|
|
93
|
+
// Handle request
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Priority Order
|
|
98
|
+
|
|
99
|
+
1. `definePageMeta({ auth })` - highest priority
|
|
100
|
+
2. `routeRules` patterns - matched by path
|
|
101
|
+
3. Default: no protection
|
|
102
|
+
|
|
103
|
+
## Prerendered Pages
|
|
104
|
+
|
|
105
|
+
Auth checks skip during prerender hydration. Session fetched client-side after hydration completes.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Server-Side Authentication
|
|
2
|
+
|
|
3
|
+
## serverAuth()
|
|
4
|
+
|
|
5
|
+
Get the Better Auth instance for advanced operations:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// server/api/custom.ts
|
|
9
|
+
export default defineEventHandler(async (event) => {
|
|
10
|
+
const auth = serverAuth()
|
|
11
|
+
// Access full Better Auth API
|
|
12
|
+
const sessions = await auth.api.listSessions({ headers: event.headers })
|
|
13
|
+
return sessions
|
|
14
|
+
})
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Module-level singleton (safe to call multiple times - returns cached instance).
|
|
18
|
+
|
|
19
|
+
### Available Server Methods
|
|
20
|
+
|
|
21
|
+
Via `serverAuth().api`:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const auth = serverAuth()
|
|
25
|
+
|
|
26
|
+
// Session management
|
|
27
|
+
await auth.api.listSessions({ headers: event.headers })
|
|
28
|
+
await auth.api.revokeSession({ sessionId: 'xxx' }, { headers: event.headers })
|
|
29
|
+
await auth.api.revokeOtherSessions({ headers: event.headers })
|
|
30
|
+
await auth.api.revokeSessions({ headers: event.headers })
|
|
31
|
+
|
|
32
|
+
// User management (with admin plugin)
|
|
33
|
+
await auth.api.setRole({ userId: 'xxx', role: 'admin' }, { headers: event.headers })
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## getUserSession()
|
|
37
|
+
|
|
38
|
+
Get current session without throwing (returns null if not authenticated):
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
export default defineEventHandler(async (event) => {
|
|
42
|
+
const result = await getUserSession(event)
|
|
43
|
+
if (!result) {
|
|
44
|
+
return { guest: true }
|
|
45
|
+
}
|
|
46
|
+
return { user: result.user }
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Returns `{ user: AuthUser, session: AuthSession } | null`.
|
|
51
|
+
|
|
52
|
+
## requireUserSession()
|
|
53
|
+
|
|
54
|
+
Enforce authentication - throws if not authenticated:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
export default defineEventHandler(async (event) => {
|
|
58
|
+
const { user, session } = await requireUserSession(event)
|
|
59
|
+
// user and session are guaranteed to exist
|
|
60
|
+
return { userId: user.id }
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- Throws `401` if not authenticated
|
|
65
|
+
- Throws `403` if user matching fails
|
|
66
|
+
|
|
67
|
+
## User Matching
|
|
68
|
+
|
|
69
|
+
Restrict access based on user properties:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// Single value - exact match
|
|
73
|
+
await requireUserSession(event, {
|
|
74
|
+
user: { role: 'admin' }
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Array - OR logic (any value matches)
|
|
78
|
+
await requireUserSession(event, {
|
|
79
|
+
user: { role: ['admin', 'moderator'] }
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// Multiple fields - AND logic (all must match)
|
|
83
|
+
await requireUserSession(event, {
|
|
84
|
+
user: { role: 'admin', verified: true }
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Custom Rules
|
|
89
|
+
|
|
90
|
+
For complex validation logic:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
await requireUserSession(event, {
|
|
94
|
+
rule: ({ user, session }) => {
|
|
95
|
+
return user.subscription?.active && user.points > 100
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// Combined with user matching
|
|
100
|
+
await requireUserSession(event, {
|
|
101
|
+
user: { verified: true },
|
|
102
|
+
rule: ({ user }) => user.subscription?.plan === 'pro'
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Pattern Examples
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// Admin-only endpoint
|
|
110
|
+
export default defineEventHandler(async (event) => {
|
|
111
|
+
const { user } = await requireUserSession(event, {
|
|
112
|
+
user: { role: 'admin' }
|
|
113
|
+
})
|
|
114
|
+
return getAdminData()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Premium feature
|
|
118
|
+
export default defineEventHandler(async (event) => {
|
|
119
|
+
await requireUserSession(event, {
|
|
120
|
+
rule: ({ user }) => ['pro', 'enterprise'].includes(user.plan)
|
|
121
|
+
})
|
|
122
|
+
return getPremiumContent()
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Owner-only resource
|
|
126
|
+
export default defineEventHandler(async (event) => {
|
|
127
|
+
const id = getRouterParam(event, 'id')
|
|
128
|
+
const { user } = await requireUserSession(event)
|
|
129
|
+
const resource = await getResource(id)
|
|
130
|
+
if (resource.ownerId !== user.id) {
|
|
131
|
+
throw createError({ statusCode: 403 })
|
|
132
|
+
}
|
|
133
|
+
return resource
|
|
134
|
+
})
|
|
135
|
+
```
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# TypeScript Types
|
|
2
|
+
|
|
3
|
+
## Module Alias
|
|
4
|
+
|
|
5
|
+
Import types from the module alias:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import type { AuthUser, AuthSession, ServerAuthContext, AppAuthClient } from '#nuxt-better-auth'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Core Types
|
|
12
|
+
|
|
13
|
+
### AuthUser
|
|
14
|
+
|
|
15
|
+
User object returned by `useUserSession()` and `requireUserSession()`:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
interface AuthUser {
|
|
19
|
+
id: string
|
|
20
|
+
email: string
|
|
21
|
+
name?: string
|
|
22
|
+
image?: string
|
|
23
|
+
emailVerified: boolean
|
|
24
|
+
createdAt: Date
|
|
25
|
+
updatedAt: Date
|
|
26
|
+
// Plus any fields from plugins (role, etc.)
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### AuthSession
|
|
31
|
+
|
|
32
|
+
Session object:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
interface AuthSession {
|
|
36
|
+
id: string
|
|
37
|
+
userId: string
|
|
38
|
+
expiresAt: Date
|
|
39
|
+
// token is filtered from exposed data
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Type Inference
|
|
44
|
+
|
|
45
|
+
Types are automatically inferred from your server config. The module uses `InferUser` and `InferSession` from Better Auth:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// Inferred from server/auth.config.ts
|
|
49
|
+
type AuthUser = InferUser<typeof authConfig>
|
|
50
|
+
type AuthSession = InferSession<typeof authConfig>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Plugin Type Augmentation
|
|
54
|
+
|
|
55
|
+
When using plugins, types extend automatically:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// With admin plugin
|
|
59
|
+
interface AuthUser {
|
|
60
|
+
// ... base fields
|
|
61
|
+
role: 'user' | 'admin'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// With 2FA plugin
|
|
65
|
+
interface AuthUser {
|
|
66
|
+
// ... base fields
|
|
67
|
+
twoFactorEnabled: boolean
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## ServerAuthContext
|
|
72
|
+
|
|
73
|
+
Available in `defineServerAuth()` callback:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
interface ServerAuthContext {
|
|
77
|
+
runtimeConfig: RuntimeConfig
|
|
78
|
+
db?: DrizzleDatabase // When NuxtHub enabled
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Using Types in Components
|
|
83
|
+
|
|
84
|
+
```vue
|
|
85
|
+
<script setup lang="ts">
|
|
86
|
+
import type { AuthUser } from '#nuxt-better-auth'
|
|
87
|
+
|
|
88
|
+
const { user } = useUserSession()
|
|
89
|
+
// user is Ref<AuthUser | null>
|
|
90
|
+
|
|
91
|
+
function greet(u: AuthUser) {
|
|
92
|
+
return `Hello, ${u.name}`
|
|
93
|
+
}
|
|
94
|
+
</script>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Using Types in Server
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
// server/utils/helpers.ts
|
|
101
|
+
import type { AuthUser, AuthSession } from '#nuxt-better-auth'
|
|
102
|
+
|
|
103
|
+
export function isAdmin(user: AuthUser): boolean {
|
|
104
|
+
return user.role === 'admin'
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Custom User Fields
|
|
109
|
+
|
|
110
|
+
Extend user type via Better Auth config:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
// server/auth.config.ts
|
|
114
|
+
export default defineServerAuth(() => ({
|
|
115
|
+
user: {
|
|
116
|
+
additionalFields: {
|
|
117
|
+
plan: { type: 'string' },
|
|
118
|
+
credits: { type: 'number' }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}))
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Types automatically include these fields:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
// AuthUser now includes:
|
|
128
|
+
interface AuthUser {
|
|
129
|
+
// ... base fields
|
|
130
|
+
plan: string
|
|
131
|
+
credits: number
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Type-Safe User Matching
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// Fully typed
|
|
139
|
+
await requireUserSession(event, {
|
|
140
|
+
user: { role: 'admin' } // TypeScript knows valid fields
|
|
141
|
+
})
|
|
142
|
+
```
|