@opensaas/stack-auth 0.1.0
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/.turbo/turbo-build.log +4 -0
- package/INTEGRATION_SUMMARY.md +425 -0
- package/README.md +445 -0
- package/dist/client/index.d.ts +38 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +23 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config/index.d.ts +50 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +115 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +160 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/lists/index.d.ts +46 -0
- package/dist/lists/index.d.ts.map +1 -0
- package/dist/lists/index.js +227 -0
- package/dist/lists/index.js.map +1 -0
- package/dist/server/index.d.ts +27 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +90 -0
- package/dist/server/index.js.map +1 -0
- package/dist/ui/components/ForgotPasswordForm.d.ts +36 -0
- package/dist/ui/components/ForgotPasswordForm.d.ts.map +1 -0
- package/dist/ui/components/ForgotPasswordForm.js +50 -0
- package/dist/ui/components/ForgotPasswordForm.js.map +1 -0
- package/dist/ui/components/SignInForm.d.ts +52 -0
- package/dist/ui/components/SignInForm.d.ts.map +1 -0
- package/dist/ui/components/SignInForm.js +66 -0
- package/dist/ui/components/SignInForm.js.map +1 -0
- package/dist/ui/components/SignUpForm.d.ts +56 -0
- package/dist/ui/components/SignUpForm.d.ts.map +1 -0
- package/dist/ui/components/SignUpForm.js +74 -0
- package/dist/ui/components/SignUpForm.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +4 -0
- package/dist/ui/index.js.map +1 -0
- package/package.json +55 -0
- package/src/client/index.ts +44 -0
- package/src/config/index.ts +140 -0
- package/src/config/types.ts +166 -0
- package/src/index.ts +44 -0
- package/src/lists/index.ts +245 -0
- package/src/server/index.ts +120 -0
- package/src/ui/components/ForgotPasswordForm.tsx +120 -0
- package/src/ui/components/SignInForm.tsx +191 -0
- package/src/ui/components/SignUpForm.tsx +238 -0
- package/src/ui/index.ts +7 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Better-Auth Integration Summary
|
|
2
|
+
|
|
3
|
+
This document summarizes the complete better-auth integration for the OpenSaas Stack.
|
|
4
|
+
|
|
5
|
+
## What Was Built
|
|
6
|
+
|
|
7
|
+
### 1. Core Package (`@opensaas/stack-auth`)
|
|
8
|
+
|
|
9
|
+
**Location:** `packages/auth/`
|
|
10
|
+
|
|
11
|
+
**Exports:**
|
|
12
|
+
|
|
13
|
+
- **Main** (`@opensaas/stack-auth`):
|
|
14
|
+
- `withAuth()` - Config wrapper that adds auth lists
|
|
15
|
+
- `authConfig()` - Auth configuration builder
|
|
16
|
+
- `getAuthLists()` - Get all auth list definitions
|
|
17
|
+
|
|
18
|
+
- **Server** (`@opensaas/stack-auth/server`):
|
|
19
|
+
- `createAuth()` - Creates better-auth instance
|
|
20
|
+
- `getSessionFromAuth()` - Session extraction helper
|
|
21
|
+
|
|
22
|
+
- **Client** (`@opensaas/stack-auth/client`):
|
|
23
|
+
- `createClient()` - Creates better-auth React client
|
|
24
|
+
|
|
25
|
+
- **UI** (`@opensaas/stack-auth/ui`):
|
|
26
|
+
- `<SignInForm />` - Pre-built sign in form
|
|
27
|
+
- `<SignUpForm />` - Pre-built sign up form
|
|
28
|
+
- `<ForgotPasswordForm />` - Pre-built password reset form
|
|
29
|
+
|
|
30
|
+
### 2. Auto-Generated Lists
|
|
31
|
+
|
|
32
|
+
The package automatically creates four lists matching better-auth's schema:
|
|
33
|
+
|
|
34
|
+
**User:**
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
{
|
|
38
|
+
id: string
|
|
39
|
+
name: string
|
|
40
|
+
email: string (unique)
|
|
41
|
+
emailVerified: boolean
|
|
42
|
+
image?: string
|
|
43
|
+
sessions: Session[]
|
|
44
|
+
accounts: Account[]
|
|
45
|
+
createdAt: Date
|
|
46
|
+
updatedAt: Date
|
|
47
|
+
// + custom fields via extendUserList
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Session:**
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
{
|
|
55
|
+
id: string
|
|
56
|
+
token: string (unique)
|
|
57
|
+
userId: string
|
|
58
|
+
expiresAt: Date
|
|
59
|
+
ipAddress?: string
|
|
60
|
+
userAgent?: string
|
|
61
|
+
user: User
|
|
62
|
+
createdAt: Date
|
|
63
|
+
updatedAt: Date
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Account:**
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
{
|
|
71
|
+
id: string
|
|
72
|
+
userId: string
|
|
73
|
+
accountId: string
|
|
74
|
+
providerId: string
|
|
75
|
+
accessToken?: string
|
|
76
|
+
refreshToken?: string
|
|
77
|
+
// ... OAuth token fields
|
|
78
|
+
password?: string
|
|
79
|
+
user: User
|
|
80
|
+
createdAt: Date
|
|
81
|
+
updatedAt: Date
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Verification:**
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
{
|
|
89
|
+
id: string
|
|
90
|
+
identifier: string
|
|
91
|
+
value: string
|
|
92
|
+
expiresAt: Date
|
|
93
|
+
createdAt: Date
|
|
94
|
+
updatedAt: Date
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3. Example Application (`examples/auth-demo`)
|
|
99
|
+
|
|
100
|
+
A complete working example showing:
|
|
101
|
+
|
|
102
|
+
- ✅ Email/password authentication
|
|
103
|
+
- ✅ Sign up, sign in, forgot password pages
|
|
104
|
+
- ✅ Session-based access control
|
|
105
|
+
- ✅ Protected admin routes
|
|
106
|
+
- ✅ Author-only post editing
|
|
107
|
+
- ✅ Auto-generated auth tables
|
|
108
|
+
|
|
109
|
+
## Usage Pattern
|
|
110
|
+
|
|
111
|
+
### Step 1: Config
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// opensaas.config.ts
|
|
115
|
+
import { withAuth, authConfig } from '@opensaas/stack-auth'
|
|
116
|
+
|
|
117
|
+
export default withAuth(
|
|
118
|
+
config({
|
|
119
|
+
db: { provider: 'sqlite', url: 'file:./dev.db' },
|
|
120
|
+
lists: {
|
|
121
|
+
/* your custom lists */
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
authConfig({
|
|
125
|
+
emailAndPassword: { enabled: true },
|
|
126
|
+
sessionFields: ['userId', 'email', 'name'],
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Step 2: Generate
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pnpm generate # Generates auth tables in Prisma schema
|
|
135
|
+
pnpm db:push # Creates database with all tables
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Step 3: Server Setup
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// lib/auth.ts
|
|
142
|
+
import { createAuth } from '@opensaas/stack-auth/server'
|
|
143
|
+
export const auth = createAuth(config)
|
|
144
|
+
export const GET = auth.handler
|
|
145
|
+
export const POST = auth.handler
|
|
146
|
+
|
|
147
|
+
// app/api/auth/[...all]/route.ts
|
|
148
|
+
export { GET, POST } from '@/lib/auth'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Step 4: Client Setup
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// lib/auth-client.ts
|
|
155
|
+
'use client'
|
|
156
|
+
import { createClient } from '@opensaas/stack-auth/client'
|
|
157
|
+
export const authClient = createClient({ baseURL: '...' })
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Step 5: Use UI Components
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// app/sign-in/page.tsx
|
|
164
|
+
import { SignInForm } from '@opensaas/stack-auth/ui'
|
|
165
|
+
import { authClient } from '@/lib/auth-client'
|
|
166
|
+
|
|
167
|
+
<SignInForm authClient={authClient} redirectTo="/admin" />
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Step 6: Access Control Works Automatically
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// opensaas.config.ts
|
|
174
|
+
lists: {
|
|
175
|
+
Post: list({
|
|
176
|
+
access: {
|
|
177
|
+
operation: {
|
|
178
|
+
create: ({ session }) => !!session, // ✅ session available!
|
|
179
|
+
update: ({ session, item }) => {
|
|
180
|
+
return session?.userId === item?.authorId
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Key Features
|
|
189
|
+
|
|
190
|
+
### 1. Zero Boilerplate
|
|
191
|
+
|
|
192
|
+
No manual User model, no manual session handling, no manual auth routes. Everything is auto-generated.
|
|
193
|
+
|
|
194
|
+
### 2. Type-Safe Sessions
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
authConfig({
|
|
198
|
+
sessionFields: ['userId', 'email', 'name', 'role'],
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Session type is inferred:
|
|
202
|
+
// { userId: string, email: string, name: string, role: string }
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 3. Extensible User Model
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
authConfig({
|
|
209
|
+
extendUserList: {
|
|
210
|
+
fields: {
|
|
211
|
+
role: select({ options: [...] }),
|
|
212
|
+
company: text(),
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 4. Pre-Built UI with Customization
|
|
219
|
+
|
|
220
|
+
All forms accept custom props and callbacks:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
<SignInForm
|
|
224
|
+
authClient={authClient}
|
|
225
|
+
redirectTo="/dashboard"
|
|
226
|
+
showSocialProviders={true}
|
|
227
|
+
socialProviders={['github', 'google']}
|
|
228
|
+
onSuccess={() => console.log('Success!')}
|
|
229
|
+
onError={(error) => console.error(error)}
|
|
230
|
+
className="my-custom-class"
|
|
231
|
+
/>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 5. Multiple Auth Methods
|
|
235
|
+
|
|
236
|
+
Configure what you need:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
authConfig({
|
|
240
|
+
emailAndPassword: { enabled: true },
|
|
241
|
+
emailVerification: { enabled: true },
|
|
242
|
+
passwordReset: { enabled: true },
|
|
243
|
+
socialProviders: {
|
|
244
|
+
github: { clientId: '...', clientSecret: '...' },
|
|
245
|
+
google: { clientId: '...', clientSecret: '...' },
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Architecture Decisions
|
|
251
|
+
|
|
252
|
+
### 1. Better-Auth vs NextAuth/Clerk
|
|
253
|
+
|
|
254
|
+
**Why better-auth?**
|
|
255
|
+
|
|
256
|
+
- TypeScript-first
|
|
257
|
+
- Framework-agnostic (works with any React framework)
|
|
258
|
+
- Simpler configuration
|
|
259
|
+
- No dependency on external services
|
|
260
|
+
- Modern security practices built-in
|
|
261
|
+
|
|
262
|
+
### 2. Auto-Generation vs Manual Setup
|
|
263
|
+
|
|
264
|
+
The package auto-generates all auth tables to:
|
|
265
|
+
|
|
266
|
+
- Reduce boilerplate
|
|
267
|
+
- Ensure consistency with better-auth schema
|
|
268
|
+
- Make updates easier (just update package version)
|
|
269
|
+
- Provide a "batteries included" experience
|
|
270
|
+
|
|
271
|
+
Users can still extend the User model via `extendUserList`.
|
|
272
|
+
|
|
273
|
+
### 3. Configurable Session Fields
|
|
274
|
+
|
|
275
|
+
Instead of including all user data in session, developers choose what they need:
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
sessionFields: ['userId', 'email', 'name']
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
This balances convenience with performance (smaller session objects).
|
|
282
|
+
|
|
283
|
+
### 4. Silent Access Control Integration
|
|
284
|
+
|
|
285
|
+
Sessions are automatically available in all access control functions. No manual `getSession()` calls needed.
|
|
286
|
+
|
|
287
|
+
### 5. Component Registry Pattern
|
|
288
|
+
|
|
289
|
+
UI components follow the stack's registry pattern:
|
|
290
|
+
|
|
291
|
+
- Pre-built components for common use cases
|
|
292
|
+
- Fully replaceable for custom designs
|
|
293
|
+
- Props-based customization for quick tweaks
|
|
294
|
+
|
|
295
|
+
## Testing the Integration
|
|
296
|
+
|
|
297
|
+
See `examples/auth-demo` for a complete working example.
|
|
298
|
+
|
|
299
|
+
### Quick Test
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
cd examples/auth-demo
|
|
303
|
+
pnpm install
|
|
304
|
+
pnpm generate
|
|
305
|
+
pnpm db:push
|
|
306
|
+
pnpm dev
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Visit `http://localhost:3003/sign-up` to create an account!
|
|
310
|
+
|
|
311
|
+
## Future Enhancements
|
|
312
|
+
|
|
313
|
+
Potential additions:
|
|
314
|
+
|
|
315
|
+
1. **Two-Factor Authentication** - Add 2FA support via better-auth plugins
|
|
316
|
+
2. **Magic Links** - Email-based passwordless auth
|
|
317
|
+
3. **Role-Based Access Control** - Built-in role checking helpers
|
|
318
|
+
4. **Admin UI Integration** - Show auth tables in admin panel
|
|
319
|
+
5. **Session Management UI** - View/revoke active sessions
|
|
320
|
+
6. **Audit Logging** - Track auth events
|
|
321
|
+
|
|
322
|
+
## Files Created
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
packages/auth/
|
|
326
|
+
├── src/
|
|
327
|
+
│ ├── config/
|
|
328
|
+
│ │ ├── index.ts # withAuth(), authConfig()
|
|
329
|
+
│ │ └── types.ts # Auth config types
|
|
330
|
+
│ ├── lists/
|
|
331
|
+
│ │ └── index.ts # User, Session, Account, Verification
|
|
332
|
+
│ ├── server/
|
|
333
|
+
│ │ └── index.ts # createAuth()
|
|
334
|
+
│ ├── client/
|
|
335
|
+
│ │ └── index.ts # createClient()
|
|
336
|
+
│ ├── ui/
|
|
337
|
+
│ │ ├── components/
|
|
338
|
+
│ │ │ ├── SignInForm.tsx
|
|
339
|
+
│ │ │ ├── SignUpForm.tsx
|
|
340
|
+
│ │ │ └── ForgotPasswordForm.tsx
|
|
341
|
+
│ │ └── index.ts
|
|
342
|
+
│ └── index.ts # Main exports
|
|
343
|
+
├── package.json
|
|
344
|
+
├── tsconfig.json
|
|
345
|
+
└── README.md
|
|
346
|
+
|
|
347
|
+
examples/auth-demo/
|
|
348
|
+
├── app/
|
|
349
|
+
│ ├── api/auth/[...all]/route.ts
|
|
350
|
+
│ ├── sign-in/page.tsx
|
|
351
|
+
│ ├── sign-up/page.tsx
|
|
352
|
+
│ └── forgot-password/page.tsx
|
|
353
|
+
├── lib/
|
|
354
|
+
│ ├── auth.ts
|
|
355
|
+
│ └── auth-client.ts
|
|
356
|
+
├── opensaas.config.ts
|
|
357
|
+
├── .env
|
|
358
|
+
└── README.md
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Performance Considerations
|
|
362
|
+
|
|
363
|
+
### Session Caching
|
|
364
|
+
|
|
365
|
+
Better-auth supports cookie caching to reduce database queries:
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
// Future enhancement
|
|
369
|
+
authConfig({
|
|
370
|
+
session: {
|
|
371
|
+
cookieCaching: true, // Validate at cookie level
|
|
372
|
+
},
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Session Field Selection
|
|
377
|
+
|
|
378
|
+
Only include necessary fields to keep session objects small:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
// Good - minimal session
|
|
382
|
+
sessionFields: ['userId']
|
|
383
|
+
|
|
384
|
+
// Less optimal - large session
|
|
385
|
+
sessionFields: ['userId', 'email', 'name', 'bio', 'preferences', ...]
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Security
|
|
389
|
+
|
|
390
|
+
### Built-in Security
|
|
391
|
+
|
|
392
|
+
Better-auth provides:
|
|
393
|
+
|
|
394
|
+
- ✅ Bcrypt password hashing
|
|
395
|
+
- ✅ CSRF protection
|
|
396
|
+
- ✅ Secure session tokens
|
|
397
|
+
- ✅ XSS protection
|
|
398
|
+
- ✅ Rate limiting (configurable)
|
|
399
|
+
|
|
400
|
+
### Environment Variables
|
|
401
|
+
|
|
402
|
+
Always set these in production:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
BETTER_AUTH_SECRET=<strong-random-secret>
|
|
406
|
+
BETTER_AUTH_URL=https://your-domain.com
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Generate secrets with:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
openssl rand -base64 32
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Conclusion
|
|
416
|
+
|
|
417
|
+
The `@opensaas/stack-auth` package provides a complete, production-ready authentication solution for OpenSaas Stack applications. It follows the stack's design principles:
|
|
418
|
+
|
|
419
|
+
- Config-first approach
|
|
420
|
+
- Self-contained field/list definitions
|
|
421
|
+
- Type-safe throughout
|
|
422
|
+
- Minimal boilerplate
|
|
423
|
+
- Extensible and customizable
|
|
424
|
+
|
|
425
|
+
Developers can go from zero to fully authenticated app in under 5 minutes! 🎉
|