mulguard 1.0.1 โ†’ 1.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/README.md CHANGED
@@ -1,93 +1,201 @@
1
- # Mukey - Modern Authentication Library
1
+ # Mulguard
2
2
 
3
- > Backend-first authentication library for Next.js and modern web applications
3
+ > A modern, backend-first authentication library for Next.js applications
4
4
 
5
- [![License](https://img.shields.io/badge/license-MUV-blue.svg)](LICENSE)
5
+ [![License: MUV](https://img.shields.io/badge/License-MUV-blue.svg)](LICENSE)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Next.js](https://img.shields.io/badge/Next.js-14.0+-black.svg)](https://nextjs.org/)
7
8
 
8
- Mukey is a modern, secure authentication library designed for Next.js applications with a backend-first architecture. It provides a simple API similar to `better-auth` and `auth.js`, while maintaining full control over your backend authentication logic.
9
+ **Mulguard** is a powerful, flexible authentication library designed specifically for Next.js applications. Built with a backend-first architecture, it gives you complete control over your authentication logic while providing a simple, intuitive API similar to popular libraries like `better-auth` and `auth.js`.
10
+
11
+ **Part of the [Mulverse](https://mulverse.com) ecosystem** - Empowering modern web applications with robust, secure authentication.
12
+
13
+ ---
14
+
15
+ ## Table of Contents
16
+
17
+ - [Features](#-features)
18
+ - [Installation](#-installation)
19
+ - [Quick Start](#-quick-start)
20
+ - [Core Concepts](#-core-concepts)
21
+ - [Authentication Methods](#-authentication-methods)
22
+ - [Configuration](#-configuration)
23
+ - [Server-Side Usage](#-server-side-usage)
24
+ - [Client-Side Usage](#-client-side-usage)
25
+ - [Components](#-components)
26
+ - [Security](#-security)
27
+ - [Backend Integration](#-backend-integration)
28
+ - [Advanced Features](#-advanced-features)
29
+ - [API Reference](#-api-reference)
30
+ - [Examples](#-examples)
31
+ - [Testing](#-testing)
32
+ - [Contributing](#-contributing)
33
+ - [License](#-license)
34
+ - [Support](#-support)
35
+
36
+ ---
9
37
 
10
38
  ## โœจ Features
11
39
 
12
- - ๐Ÿ” **Multiple Auth Methods**
13
- - Email/Password authentication
14
- - OAuth 2.1 (Google, GitHub, etc.)
15
- - PassKey/WebAuthn support
16
- - Two-Factor Authentication (2FA/TOTP)
17
-
18
- - ๐ŸŽฏ **Account Picker**
19
- - Remember last logged-in users
20
- - Quick re-login experience
21
- - Encrypted local storage
22
-
23
- - ๐Ÿ”’ **Security First**
24
- - CSRF protection
25
- - XSS prevention
26
- - Input validation & sanitization
27
- - Security headers
28
- - Rate limiting utilities
29
-
30
- - โšก **Next.js Optimized**
31
- - Server Components support
32
- - Client hooks (`useAuth`, `useSession`)
33
- - Middleware integration
34
- - API route handlers
35
-
36
- - ๐Ÿ”Œ **Backend-First**
37
- - No database adapter required
38
- - Works with your existing backend API
39
- - Mulink integration support
40
- - Full TypeScript support
40
+ ### ๐Ÿ” Multiple Authentication Methods
41
+ - **Email/Password** - Traditional credential-based authentication
42
+ - **OAuth 2.1** - Support for Google, GitHub, and other OAuth providers
43
+ - **PassKey/WebAuthn** - Passwordless authentication with biometric support
44
+ - **Two-Factor Authentication (2FA/TOTP)** - Time-based one-time passwords with backup codes
45
+ - **OTP** - One-time password authentication
46
+
47
+ ### ๐ŸŽฏ Account Picker
48
+ - Remember last logged-in users
49
+ - Quick re-login experience
50
+ - Encrypted local storage for security
51
+ - Configurable account limits
52
+
53
+ ### ๐Ÿ”’ Security First
54
+ - **CSRF Protection** - Token-based cross-site request forgery protection
55
+ - **XSS Prevention** - Input sanitization and HTML escaping
56
+ - **Security Headers** - Automatic security headers configuration
57
+ - **Input Validation** - Comprehensive validation and sanitization
58
+ - **Rate Limiting** - Built-in rate limiting utilities
59
+ - **Secure Cookies** - HttpOnly, Secure, SameSite cookie configuration
60
+
61
+ ### โšก Next.js Optimized
62
+ - **Server Components** - Full support for React Server Components
63
+ - **Client Hooks** - `useAuth`, `useSession` for client-side state management
64
+ - **Middleware Integration** - Seamless Next.js middleware support
65
+ - **API Route Handlers** - Pre-built route handlers for authentication endpoints
66
+ - **Server Actions** - Native support for Next.js Server Actions
67
+
68
+ ### ๐Ÿ”Œ Backend-First Architecture
69
+ - **No Database Adapter Required** - Works with your existing backend API
70
+ - **Custom Actions** - Implement your own authentication logic
71
+ - **Flexible Integration** - Works with any backend (REST, GraphQL, etc.)
72
+ - **Mulink Integration** - Optional integration with Mulink API client
73
+ - **Full TypeScript Support** - Complete type safety throughout
74
+
75
+ ---
41
76
 
42
77
  ## ๐Ÿ“ฆ Installation
43
78
 
44
79
  ```bash
45
- npm install mukey
80
+ npm install mulguard
46
81
  ```
47
82
 
83
+ ### Peer Dependencies
84
+
85
+ Mulguard requires the following peer dependencies:
86
+
87
+ ```bash
88
+ npm install next@>=14.0.0 react@>=18.0.0 react-dom@>=18.0.0
89
+ ```
90
+
91
+ ---
92
+
48
93
  ## ๐Ÿš€ Quick Start
49
94
 
50
95
  ### 1. Create Auth Configuration
51
96
 
52
- ```typescript
53
- // lib/auth.ts
54
- import { mukey } from 'mukey'
55
- // import { apiClient } from '@mulink/client' // Optional: Use Mulink
97
+ Create a new file `lib/auth.ts`:
56
98
 
57
- export const auth = mukey({
58
- // Option 1: Use Mulink API client
59
- // apiClient: apiClient,
99
+ ```typescript
100
+ import { mulguard } from 'mulguard'
101
+ import type { EmailCredentials, AuthResult, Session } from 'mulguard'
102
+ import { db } from '@/lib/db'
103
+ import { comparePassword } from '@/lib/password'
60
104
 
61
- // Option 2: Use baseURL
62
- baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001',
63
-
105
+ export const auth = mulguard({
106
+ // Session configuration
64
107
  session: {
65
- cookieName: '__mukey_session',
108
+ cookieName: '__mulguard_session',
66
109
  expiresIn: 60 * 60 * 24 * 7, // 7 days
110
+ httpOnly: true,
111
+ secure: process.env.NODE_ENV === 'production', // HTTPS only in production
112
+ sameSite: 'lax',
113
+ },
114
+
115
+ // Required: Implement your authentication actions
116
+ actions: {
117
+ signIn: {
118
+ // โœ… Unified interface: auth.signIn('credentials', {...}) or auth.signIn.email({...})
119
+ email: async (credentials: EmailCredentials): Promise<AuthResult> => {
120
+ // Your custom sign-in logic
121
+ const user = await db.user.findUnique({
122
+ where: { email: credentials.email }
123
+ })
124
+
125
+ if (!user || !await comparePassword(credentials.password, user.password)) {
126
+ return {
127
+ success: false,
128
+ error: 'Invalid credentials',
129
+ errorCode: 'INVALID_CREDENTIALS'
130
+ }
131
+ }
132
+
133
+ const session: Session = {
134
+ user: {
135
+ id: user.id,
136
+ email: user.email,
137
+ name: user.name,
138
+ emailVerified: user.emailVerified,
139
+ },
140
+ expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
141
+ }
142
+
143
+ return { success: true, user: session.user, session }
144
+ },
145
+ },
146
+
147
+ getSession: async (): Promise<Session | null> => {
148
+ // Your custom session retrieval logic
149
+ // Can read from cookie or database
150
+ return await db.getSession()
151
+ },
152
+
153
+ signOut: async () => {
154
+ // Your custom sign-out logic
155
+ await db.invalidateSession()
156
+ return { success: true }
157
+ },
67
158
  },
68
159
 
160
+ // Optional: OAuth providers (auto-generates OAuth actions)
69
161
  providers: {
70
162
  oauth: {
71
163
  google: {
72
164
  clientId: process.env.GOOGLE_CLIENT_ID!,
165
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET, // Server-side only
73
166
  redirectUri: `${process.env.NEXT_PUBLIC_URL}/api/auth/callback/google`,
74
167
  scopes: ['openid', 'profile', 'email'],
75
168
  },
169
+ github: {
170
+ clientId: process.env.GITHUB_CLIENT_ID!,
171
+ clientSecret: process.env.GITHUB_CLIENT_SECRET,
172
+ redirectUri: `${process.env.NEXT_PUBLIC_URL}/api/auth/callback/github`,
173
+ scopes: ['user:email'],
174
+ },
76
175
  },
77
176
  },
78
177
 
79
- accountPicker: {
80
- enabled: true,
81
- maxAccounts: 3,
178
+ // Optional: Callbacks for lifecycle events
179
+ callbacks: {
180
+ onSignIn: async (user, session) => {
181
+ // Track sign-in analytics, update last login, etc.
182
+ console.log('User signed in:', user.email)
183
+ },
184
+ onError: async (error, context) => {
185
+ // Log errors for monitoring
186
+ console.error(`Auth error in ${context}:`, error)
187
+ },
82
188
  },
83
189
  })
84
190
  ```
85
191
 
192
+ > ๐Ÿ“– **For a complete guide with best practices**, see [GUIDE.md](./GUIDE.md)
193
+
86
194
  ### 2. Server-Side Usage
87
195
 
88
196
  ```typescript
89
197
  // app/dashboard/page.tsx
90
- import { getServerSession } from 'mukey/server'
198
+ import { getServerSession } from 'mulguard/server'
91
199
  import { auth } from '@/lib/auth'
92
200
  import { redirect } from 'next/navigation'
93
201
 
@@ -98,7 +206,12 @@ export default async function DashboardPage() {
98
206
  redirect('/login')
99
207
  }
100
208
 
101
- return <div>Welcome, {session.user.name}!</div>
209
+ return (
210
+ <div>
211
+ <h1>Welcome, {session.user.name}!</h1>
212
+ <p>Email: {session.user.email}</p>
213
+ </div>
214
+ )
102
215
  }
103
216
  ```
104
217
 
@@ -108,7 +221,7 @@ export default async function DashboardPage() {
108
221
  // app/login/page.tsx
109
222
  'use client'
110
223
 
111
- import { useAuth } from 'mukey/client'
224
+ import { useAuth } from 'mulguard/client'
112
225
  import { auth } from '@/lib/auth'
113
226
  import { useState } from 'react'
114
227
 
@@ -119,9 +232,19 @@ export default function LoginPage() {
119
232
 
120
233
  const handleSubmit = async (e: React.FormEvent) => {
121
234
  e.preventDefault()
122
- const result = await signIn.email({ email, password })
235
+
236
+ // โœ… Unified interface (recommended)
237
+ const result = await signIn('credentials', { email, password })
238
+
239
+ // Or use direct method:
240
+ // const result = await signIn.email({ email, password })
241
+
123
242
  if (result.success) {
124
243
  // Redirect to dashboard
244
+ window.location.href = '/dashboard'
245
+ } else {
246
+ // Handle error
247
+ alert(result.error)
125
248
  }
126
249
  }
127
250
 
@@ -135,12 +258,14 @@ export default function LoginPage() {
135
258
  value={email}
136
259
  onChange={(e) => setEmail(e.target.value)}
137
260
  placeholder="Email"
261
+ required
138
262
  />
139
263
  <input
140
264
  type="password"
141
265
  value={password}
142
266
  onChange={(e) => setPassword(e.target.value)}
143
267
  placeholder="Password"
268
+ required
144
269
  />
145
270
  <button type="submit">Sign In</button>
146
271
  </form>
@@ -152,7 +277,7 @@ export default function LoginPage() {
152
277
 
153
278
  ```typescript
154
279
  // middleware.ts
155
- import { createAuthMiddleware } from 'mukey/middleware'
280
+ import { createAuthMiddleware } from 'mulguard/middleware'
156
281
  import { auth } from '@/lib/auth'
157
282
 
158
283
  export default createAuthMiddleware(auth, {
@@ -160,44 +285,191 @@ export default createAuthMiddleware(auth, {
160
285
  redirectTo: '/login',
161
286
  redirectIfAuthenticated: '/dashboard',
162
287
  })
288
+
289
+ export const config = {
290
+ matcher: ['/dashboard/:path*', '/profile/:path*'],
291
+ }
292
+ ```
293
+
294
+ ---
295
+
296
+ ## ๐ŸŽ“ Core Concepts
297
+
298
+ ### Backend-First Architecture
299
+
300
+ Mulguard follows a **backend-first** approach, meaning you implement your own authentication logic through **actions**. This gives you:
301
+
302
+ - **Full Control** - Complete control over your authentication flow
303
+ - **Flexibility** - Works with any backend architecture
304
+ - **No Lock-in** - No database adapter required
305
+ - **Custom Logic** - Implement business-specific authentication rules
306
+
307
+ ### Actions
308
+
309
+ Actions are functions you provide to handle authentication operations:
310
+
311
+ ```typescript
312
+ actions: {
313
+ signIn: {
314
+ email: async (credentials) => { /* ... */ },
315
+ oauth: async (provider) => { /* ... */ },
316
+ passkey: async (options) => { /* ... */ },
317
+ },
318
+ signUp: async (data) => { /* ... */ },
319
+ signOut: async () => { /* ... */ },
320
+ getSession: async () => { /* ... */ },
321
+ // ... more actions
322
+ }
323
+ ```
324
+
325
+ ### Sessions
326
+
327
+ Sessions are stored in HTTP-only cookies and contain:
328
+
329
+ ```typescript
330
+ interface Session {
331
+ user: {
332
+ id: string
333
+ email: string
334
+ name?: string
335
+ avatar?: string
336
+ emailVerified?: boolean
337
+ }
338
+ expiresAt: Date
339
+ accessToken?: string
340
+ refreshToken?: string
341
+ tokenType?: string
342
+ expiresIn?: number
343
+ }
344
+ ```
345
+
346
+ ---
347
+
348
+ ## ๐Ÿ” Authentication Methods
349
+
350
+ ### Unified Sign-In Interface
351
+
352
+ Mulguard provides a **unified interface** for all authentication methods, similar to auth.js:
353
+
354
+ ```typescript
355
+ // โœ… Unified interface (recommended)
356
+ await auth.signIn('credentials', { email: 'user@example.com', password: 'password123' })
357
+ await auth.signIn('google')
358
+ await auth.signIn('otp', { email: 'user@example.com', code: '123456' })
359
+ await auth.signIn('passkey', { userId: 'user-id' })
360
+
361
+ // โœ… Direct methods (for backward compatibility)
362
+ await auth.signIn.email({ email: 'user@example.com', password: 'password123' })
363
+ await auth.signIn.oauth('google')
364
+ await auth.signIn.otp('user@example.com', '123456')
365
+ ```
366
+
367
+ ### Email/Password Authentication
368
+
369
+ ```typescript
370
+ // Using unified interface
371
+ const result = await auth.signIn('credentials', {
372
+ email: 'user@example.com',
373
+ password: 'password123',
374
+ })
375
+
376
+ // Or using direct method
377
+ const result = await auth.signIn.email({
378
+ email: 'user@example.com',
379
+ password: 'password123',
380
+ })
381
+
382
+ if (result.success) {
383
+ console.log('Signed in:', result.user)
384
+ } else {
385
+ console.error('Error:', result.error, result.errorCode)
386
+ }
163
387
  ```
164
388
 
165
- ## ๐Ÿ“š Documentation
389
+ ### OAuth Authentication
166
390
 
167
- - [Getting Started](./docs/GETTING_STARTED.md)
168
- - [Authentication Methods](./docs/AUTH_METHODS.md)
169
- - [Server-Side Usage](./docs/SERVER_USAGE.md)
170
- - [Client-Side Usage](./docs/CLIENT_USAGE.md)
171
- - [Security](./docs/SECURITY.md)
172
- - [Backend Integration](./docs/BACKEND_INTEGRATION.md)
173
- - [API Reference](./docs/API_REFERENCE.md)
391
+ ```typescript
392
+ // Initiate OAuth flow (unified interface)
393
+ const { url } = await auth.signIn('google')
394
+ window.location.href = url
395
+
396
+ // Or using direct method
397
+ const { url } = await auth.signIn.oauth('google')
398
+ window.location.href = url
399
+
400
+ // Handle callback (in your API route)
401
+ const result = await auth.oauthCallback(provider, code, state)
402
+
403
+ // โœ… OAuth providers are auto-configured when you add them to providers.oauth
404
+ // No need to implement oauth action manually!
405
+ ```
406
+
407
+ ### PassKey/WebAuthn Authentication
408
+
409
+ ```typescript
410
+ // Register PassKey
411
+ const result = await auth.passkey.register({
412
+ name: 'My iPhone',
413
+ userId: 'user-id',
414
+ })
415
+
416
+ // Authenticate with PassKey
417
+ const result = await auth.signIn.passkey({ userId: 'user-id' })
418
+ ```
419
+
420
+ ### Two-Factor Authentication (2FA)
421
+
422
+ ```typescript
423
+ // Enable 2FA
424
+ const enableResult = await auth.twoFactor.enable()
425
+ // Display QR code to user
174
426
 
175
- ## ๐Ÿ”ง Configuration
427
+ // Verify 2FA code
428
+ const verifyResult = await auth.twoFactor.verify('123456')
429
+
430
+ // Check if 2FA is enabled
431
+ const isEnabled = await auth.twoFactor.isEnabled()
432
+ ```
433
+
434
+ ---
435
+
436
+ ## โš™๏ธ Configuration
176
437
 
177
438
  ### Full Configuration Options
178
439
 
179
440
  ```typescript
180
- import { mukey } from 'mukey'
441
+ import { mulguard } from 'mulguard'
181
442
 
182
- export const auth = mukey({
183
- // API Client (from Mulink) or baseURL
184
- apiClient: apiClient, // Optional
185
- baseURL: 'http://localhost:3001', // Required if apiClient not provided
186
-
443
+ export const auth = mulguard({
187
444
  // Session configuration
188
445
  session: {
189
- cookieName: '__mukey_session',
446
+ cookieName: '__mulguard_session',
190
447
  expiresIn: 60 * 60 * 24 * 7, // 7 days in seconds
191
448
  httpOnly: true,
192
449
  secure: process.env.NODE_ENV === 'production',
193
450
  sameSite: 'lax',
451
+ path: '/',
452
+ domain: undefined,
453
+ cacheTtl: 5000, // Session cache TTL in milliseconds
454
+ },
455
+
456
+ // Required: Authentication actions
457
+ actions: {
458
+ signIn: {
459
+ email: async (credentials) => { /* ... */ },
460
+ // Optional: oauth, passkey, otp
461
+ },
462
+ getSession: async () => { /* ... */ },
463
+ signOut: async () => { /* ... */ },
464
+ // Optional: signUp, resetPassword, verifyEmail, refreshSession, etc.
194
465
  },
195
466
 
196
- // OAuth providers
467
+ // Optional: OAuth providers
197
468
  providers: {
198
469
  oauth: {
199
470
  google: {
200
471
  clientId: '...',
472
+ clientSecret: '...', // Server-side only
201
473
  redirectUri: '...',
202
474
  scopes: ['openid', 'profile', 'email'],
203
475
  name: 'Google',
@@ -210,20 +482,20 @@ export const auth = mukey({
210
482
  },
211
483
  },
212
484
 
213
- // 2FA configuration
485
+ // Optional: Two-Factor Authentication
214
486
  twoFactor: {
215
487
  enabled: true,
216
488
  },
217
489
 
218
- // Account Picker
490
+ // Optional: Account Picker
219
491
  accountPicker: {
220
492
  enabled: true,
221
493
  maxAccounts: 3,
222
494
  encryptStorage: true,
223
- storageKey: '__mukey_accounts',
495
+ storageKey: '__mulguard_accounts',
224
496
  },
225
497
 
226
- // Security
498
+ // Optional: Security settings
227
499
  security: {
228
500
  csrfProtection: true,
229
501
  rateLimiting: {
@@ -231,15 +503,132 @@ export const auth = mukey({
231
503
  windowMs: 15 * 60 * 1000, // 15 minutes
232
504
  },
233
505
  },
506
+
507
+ // Optional: Callbacks
508
+ callbacks: {
509
+ onSignIn: async (user, session) => {
510
+ // Called after successful sign-in
511
+ },
512
+ onSignOut: async (user) => {
513
+ // Called after sign-out
514
+ },
515
+ onSessionExpired: async (session) => {
516
+ // Called when session expires
517
+ },
518
+ onError: async (error, context) => {
519
+ // Called on authentication errors
520
+ },
521
+ },
522
+
523
+ // Optional: Token refresh configuration
524
+ tokenRefresh: {
525
+ enabled: true,
526
+ refreshThreshold: 300, // 5 minutes before expiration
527
+ maxRetries: 0,
528
+ retryDelay: 1000,
529
+ rateLimit: 1, // 1 attempt per minute
530
+ autoSignOutOnFailure: true,
531
+ redirectToLogin: '/login',
532
+ },
234
533
  })
235
534
  ```
236
535
 
536
+ ---
537
+
538
+ ## ๐Ÿ–ฅ๏ธ Server-Side Usage
539
+
540
+ ### Get Server Session
541
+
542
+ ```typescript
543
+ import { getServerSession } from 'mulguard/server'
544
+ import { auth } from '@/lib/auth'
545
+
546
+ // In Server Components
547
+ const session = await getServerSession(auth)
548
+
549
+ // In API Routes
550
+ export async function GET(request: Request) {
551
+ const session = await getServerSession(auth)
552
+ if (!session) {
553
+ return new Response('Unauthorized', { status: 401 })
554
+ }
555
+ return Response.json({ user: session.user })
556
+ }
557
+ ```
558
+
559
+ ### Server Actions
560
+
561
+ ```typescript
562
+ 'use server'
563
+
564
+ import { auth } from '@/lib/auth'
565
+
566
+ export async function signInAction(email: string, password: string) {
567
+ const result = await auth.signIn.email({ email, password })
568
+ return result
569
+ }
570
+ ```
571
+
572
+ ### API Route Handlers
573
+
574
+ ```typescript
575
+ // app/api/auth/[...mulguard]/route.ts
576
+ import { createAuthHandler } from 'mulguard/handlers/route'
577
+ import { auth } from '@/lib/auth'
578
+
579
+ export const { GET, POST } = createAuthHandler(auth)
580
+ ```
581
+
582
+ ---
583
+
584
+ ## ๐Ÿ’ป Client-Side Usage
585
+
586
+ ### React Hooks
587
+
588
+ ```typescript
589
+ 'use client'
590
+
591
+ import { useAuth, useSession } from 'mulguard/client'
592
+ import { auth } from '@/lib/auth'
593
+
594
+ export function AuthComponent() {
595
+ const { signIn, signOut, isLoading } = useAuth(auth)
596
+ const { session, isLoading: sessionLoading } = useSession(auth)
597
+
598
+ // Use hooks...
599
+ }
600
+ ```
601
+
602
+ ### Auth Provider
603
+
604
+ ```typescript
605
+ // app/layout.tsx
606
+ 'use client'
607
+
608
+ import { AuthProvider } from 'mulguard/client'
609
+ import { auth } from '@/lib/auth'
610
+
611
+ export default function RootLayout({ children }) {
612
+ return (
613
+ <html>
614
+ <body>
615
+ <AuthProvider auth={auth}>
616
+ {children}
617
+ </AuthProvider>
618
+ </body>
619
+ </html>
620
+ )
621
+ }
622
+ ```
623
+
624
+ ---
625
+
237
626
  ## ๐ŸŽจ Components
238
627
 
239
628
  ### Account Picker
240
629
 
241
630
  ```typescript
242
- import { AccountPicker } from 'mukey'
631
+ import { AccountPicker } from 'mulguard'
243
632
 
244
633
  <AccountPicker
245
634
  auth={auth}
@@ -256,7 +645,7 @@ import { AccountPicker } from 'mukey'
256
645
  ### OAuth Button
257
646
 
258
647
  ```typescript
259
- import { OAuthButton } from 'mukey'
648
+ import { OAuthButton } from 'mulguard'
260
649
 
261
650
  <OAuthButton
262
651
  auth={auth}
@@ -264,13 +653,18 @@ import { OAuthButton } from 'mukey'
264
653
  onSuccess={() => {
265
654
  // Handle success
266
655
  }}
267
- />
656
+ onError={(error) => {
657
+ // Handle error
658
+ }}
659
+ >
660
+ Sign in with Google
661
+ </OAuthButton>
268
662
  ```
269
663
 
270
- ### 2FA Setup
664
+ ### Two-Factor Setup
271
665
 
272
666
  ```typescript
273
- import { TwoFactorSetup } from 'mukey'
667
+ import { TwoFactorSetup } from 'mulguard'
274
668
 
275
669
  <TwoFactorSetup
276
670
  auth={auth}
@@ -280,53 +674,286 @@ import { TwoFactorSetup } from 'mukey'
280
674
  />
281
675
  ```
282
676
 
677
+ ### PassKey Components
678
+
679
+ ```typescript
680
+ import { PassKeyButton, PassKeyRegister } from 'mulguard'
681
+
682
+ // Register PassKey
683
+ <PassKeyRegister auth={auth} />
684
+
685
+ // Authenticate with PassKey
686
+ <PassKeyButton auth={auth} />
687
+ ```
688
+
689
+ ---
690
+
691
+ ## ๐Ÿ”’ Security
692
+
693
+ Mulguard implements **comprehensive security features** with automatic input validation and sanitization:
694
+
695
+ ### โœ… Built-in Security Features
696
+
697
+ #### Input Validation & Sanitization
698
+ - **Automatic email validation** - Validates and sanitizes email addresses
699
+ - **Password length checks** - Prevents DoS attacks with extremely long passwords
700
+ - **Provider validation** - Sanitizes OAuth provider strings to prevent injection
701
+ - **OTP code validation** - Validates OTP code format before processing
702
+ - **XSS Prevention** - Automatic HTML escaping and input sanitization
703
+
704
+ #### CSRF Protection
705
+ - Token-based CSRF protection for OAuth flows
706
+ - State parameter validation with constant-time comparison
707
+ - Secure state storage (pluggable for production - Redis, Database, etc.)
708
+
709
+ #### Error Handling
710
+ - **Generic error messages** - Prevents information disclosure
711
+ - **Error codes** - Programmatic error handling without exposing details
712
+ - **Security logging** - Logs authentication events (with sensitive data masked)
713
+
714
+ #### Secure Cookies
715
+ - HttpOnly cookies (prevents JavaScript access)
716
+ - Secure flag in production (HTTPS only)
717
+ - SameSite attribute (CSRF protection)
718
+ - Configurable expiration
719
+
720
+ #### Rate Limiting
721
+ - Configurable rate limiting
722
+ - Client-side tracking
723
+ - Automatic throttling
724
+ - Circuit breaker pattern for token refresh
725
+
726
+ ### Security Best Practices
727
+
728
+ ```typescript
729
+ // โœ… Good: Generic error messages
730
+ return {
731
+ success: false,
732
+ error: 'Invalid credentials',
733
+ errorCode: 'INVALID_CREDENTIALS'
734
+ }
735
+
736
+ // โŒ Bad: Information disclosure
737
+ return {
738
+ success: false,
739
+ error: 'User not found with email: user@example.com'
740
+ }
741
+ ```
742
+
743
+ ### Security Logging
744
+
745
+ All authentication events are automatically logged with sensitive data masked:
746
+
747
+ ```typescript
748
+ // Logs show: "Sign in successful" with email: "use***"
749
+ // Never logs full email addresses or passwords
750
+ ```
751
+
752
+ For detailed security documentation, see the [Security Guide](./docs/SECURITY.md) and [Complete Guide](./GUIDE.md).
753
+
754
+ ---
755
+
283
756
  ## ๐Ÿ”Œ Backend Integration
284
757
 
285
- Mukey expects your backend to provide the following endpoints:
758
+ Mulguard is designed to work with your existing backend. You implement the authentication logic through **actions**, which can:
286
759
 
287
- ### Authentication Endpoints
760
+ - Connect to your database
761
+ - Call your API endpoints
762
+ - Use your existing authentication services
763
+ - Integrate with third-party services
288
764
 
289
- - `POST /api/auth/sign-in` - Sign in with email/password
290
- - `POST /api/auth/sign-up` - Register new user
291
- - `POST /api/auth/sign-out` - Sign out
292
- - `GET /api/auth/session` - Get current session
293
- - `POST /api/auth/reset-password` - Request password reset
294
- - `POST /api/auth/verify-email` - Verify email address
765
+ ### Example: Database Integration
295
766
 
296
- ### OAuth Endpoints
767
+ ```typescript
768
+ import { mulguard } from 'mulguard'
769
+ import { db } from '@/lib/db'
770
+ import { comparePassword, hashPassword } from '@/lib/password'
771
+
772
+ export const auth = mulguard({
773
+ actions: {
774
+ signIn: {
775
+ email: async ({ email, password }) => {
776
+ const user = await db.user.findUnique({ where: { email } })
777
+
778
+ if (!user || !await comparePassword(password, user.password)) {
779
+ return { success: false, error: 'Invalid credentials' }
780
+ }
781
+
782
+ return {
783
+ success: true,
784
+ user: {
785
+ id: user.id,
786
+ email: user.email,
787
+ name: user.name,
788
+ },
789
+ session: {
790
+ user: { /* ... */ },
791
+ expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
792
+ },
793
+ }
794
+ },
795
+ },
796
+ // ... more actions
797
+ },
798
+ })
799
+ ```
297
800
 
298
- - `GET /api/auth/oauth/:provider` - Initiate OAuth flow
299
- - `POST /api/auth/oauth/:provider/callback` - Handle OAuth callback
801
+ ### Example: API Integration
300
802
 
301
- ### 2FA Endpoints
803
+ ```typescript
804
+ import { mulguard } from 'mulguard'
805
+
806
+ export const auth = mulguard({
807
+ actions: {
808
+ signIn: {
809
+ email: async ({ email, password }) => {
810
+ const response = await fetch('https://api.example.com/auth/signin', {
811
+ method: 'POST',
812
+ headers: { 'Content-Type': 'application/json' },
813
+ body: JSON.stringify({ email, password }),
814
+ })
815
+
816
+ if (!response.ok) {
817
+ return { success: false, error: 'Authentication failed' }
818
+ }
819
+
820
+ const data = await response.json()
821
+ return {
822
+ success: true,
823
+ user: data.user,
824
+ session: data.session,
825
+ }
826
+ },
827
+ },
828
+ },
829
+ })
830
+ ```
302
831
 
303
- - `POST /api/auth/2fa/enable` - Enable 2FA
304
- - `POST /api/auth/2fa/verify` - Verify 2FA code
305
- - `POST /api/auth/2fa/disable` - Disable 2FA
306
- - `POST /api/auth/2fa/regenerate` - Generate backup codes
307
- - `GET /api/auth/2fa/status` - Check 2FA status
832
+ ---
308
833
 
309
- ### PassKey Endpoints
834
+ ## ๐Ÿš€ Advanced Features
310
835
 
311
- - `POST /api/auth/passkey/register` - Register PassKey
312
- - `POST /api/auth/passkey/authenticate` - Authenticate with PassKey
313
- - `GET /api/auth/passkey/list` - List registered PassKeys
314
- - `DELETE /api/auth/passkey/:id` - Remove PassKey
836
+ ### Token Refresh
315
837
 
316
- See [Backend Integration Guide](./docs/BACKEND_INTEGRATION.md) for detailed API specifications.
838
+ Automatic token refresh is built-in when you provide a `refreshSession` action:
317
839
 
318
- ## ๐Ÿ”’ Security
840
+ ```typescript
841
+ actions: {
842
+ refreshSession: async () => {
843
+ // Your token refresh logic
844
+ const newSession = await yourApi.refreshToken()
845
+ return newSession
846
+ },
847
+ }
848
+ ```
319
849
 
320
- Mukey implements multiple security features:
850
+ ### Custom Callbacks
321
851
 
322
- - **CSRF Protection** - Token-based CSRF protection
323
- - **XSS Prevention** - Input sanitization and HTML escaping
324
- - **Rate Limiting** - Client-side rate limit tracking
325
- - **Security Headers** - Automatic security headers
326
- - **Input Validation** - Comprehensive input validation
327
- - **Secure Cookies** - HttpOnly, Secure, SameSite cookies
852
+ ```typescript
853
+ callbacks: {
854
+ onSignIn: async (user, session) => {
855
+ // Track sign-in analytics
856
+ await analytics.track('user_signed_in', { userId: user.id })
857
+ },
858
+ onSignOut: async (user) => {
859
+ // Cleanup logic
860
+ await cleanupUserSession(user.id)
861
+ },
862
+ onError: async (error, context) => {
863
+ // Error logging
864
+ console.error(`Auth error in ${context}:`, error)
865
+ },
866
+ }
867
+ ```
868
+
869
+ ### OAuth State Store
870
+
871
+ For production, use a persistent OAuth state store:
872
+
873
+ ```typescript
874
+ import { createRedisOAuthStateStore } from 'mulguard'
875
+
876
+ const auth = mulguard({
877
+ oauthStateStore: createRedisOAuthStateStore(redisClient),
878
+ // ... rest of config
879
+ })
880
+ ```
881
+
882
+ ---
883
+
884
+ ## ๐Ÿ“š API Reference
885
+
886
+ ### Core Functions
887
+
888
+ #### `mulguard(config: MulguardConfig): MulguardInstance`
889
+
890
+ Creates a new Mulguard authentication instance.
891
+
892
+ #### `getServerSession(auth: MulguardInstance): Promise<Session | null>`
893
+
894
+ Gets the current session on the server.
895
+
896
+ ### Client Hooks
897
+
898
+ #### `useAuth(auth: MulguardInstance)`
899
+
900
+ Returns authentication methods and state.
901
+
902
+ ```typescript
903
+ const { signIn, signOut, isLoading } = useAuth(auth)
904
+ ```
905
+
906
+ #### `useSession(auth: MulguardInstance)`
907
+
908
+ Returns the current session.
909
+
910
+ ```typescript
911
+ const { session, isLoading } = useSession(auth)
912
+ ```
913
+
914
+ ### Instance Methods
915
+
916
+ #### `auth.getSession(): Promise<Session | null>`
917
+
918
+ Gets the current session.
919
+
920
+ #### `auth.signIn.email(credentials): Promise<AuthResult>`
921
+
922
+ Signs in with email and password.
923
+
924
+ #### `auth.signIn.oauth(provider): Promise<{ url: string; state: string }>`
925
+
926
+ Initiates OAuth flow.
328
927
 
329
- See [Security Guide](./docs/SECURITY.md) for more details.
928
+ #### `auth.signOut(): Promise<{ success: boolean }>`
929
+
930
+ Signs out the current user.
931
+
932
+ For complete API documentation, see the [API Reference](./docs/API_REFERENCE.md).
933
+
934
+ ---
935
+
936
+ ## ๐Ÿ“– Examples & Guides
937
+
938
+ ### Complete Guide
939
+
940
+ ๐Ÿ“š **[Complete Usage Guide](./GUIDE.md)** - Comprehensive guide with:
941
+ - Best practices for writing `auth.ts`
942
+ - Production-ready examples
943
+ - Security recommendations
944
+ - Backend integration patterns
945
+ - Advanced usage examples
946
+
947
+ ### Code Examples
948
+
949
+ - **[Basic Email Authentication](./src/examples/email-auth.ts)** - Simple email/password setup
950
+ - **[OAuth Authentication](./src/examples/oauth-auth.ts)** - Google, GitHub, etc.
951
+ - **[PassKey Authentication](./src/examples/passkey-auth.ts)** - WebAuthn/PassKey setup
952
+ - **[Two-Factor Authentication](./src/examples/two-factor-auth.ts)** - 2FA/TOTP implementation
953
+ - **[Middleware Integration](./src/examples/middleware-example.ts)** - Next.js middleware
954
+ - **[Server Components](./src/examples/server-component-example.tsx)** - Server-side usage
955
+
956
+ ---
330
957
 
331
958
  ## ๐Ÿงช Testing
332
959
 
@@ -339,30 +966,77 @@ npm run test:watch
339
966
 
340
967
  # Coverage
341
968
  npm run test:coverage
969
+
970
+ # Type checking
971
+ npm run type-check
342
972
  ```
343
973
 
344
- ## ๐Ÿš€ CI/CD
974
+ ---
975
+
976
+ ## ๐Ÿค Contributing
977
+
978
+ Contributions are welcome! Please read our contributing guidelines before submitting a pull request.
979
+
980
+ 1. Fork the repository
981
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
982
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
983
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
984
+ 5. Open a Pull Request
985
+
986
+ ### Development Setup
345
987
 
346
- This project uses GitHub Actions with npm Trusted Publisher for secure publishing.
988
+ ```bash
989
+ # Clone the repository
990
+ git clone https://github.com/mulverse/mulguard.git
991
+
992
+ # Install dependencies
993
+ npm install
347
994
 
348
- - **CI**: Runs on every push/PR (lint, test, build)
349
- - **Publishing**: Automatic publishing via Changesets or manual release
350
- - **Security**: Uses OIDC (OpenID Connect) for authentication
995
+ # Run development build
996
+ npm run dev
351
997
 
352
- See [README_CI.md](./README_CI.md) for setup instructions.
998
+ # Run tests
999
+ npm test
1000
+ ```
1001
+
1002
+ ---
353
1003
 
354
1004
  ## ๐Ÿ“ License
355
1005
 
356
- MUV License - See [LICENSE](./LICENSE) file for details.
1006
+ This project is licensed under the **MUV (Mulverse M.U.V General Public License)**.
357
1007
 
358
- ## ๐Ÿค Contributing
1008
+ Copyright (C) 2022 Mulverse Inc.
1009
+
1010
+ See the [LICENSE](./LICENSE) file for details.
1011
+
1012
+ ---
1013
+
1014
+ ## ๐Ÿ’ฌ Support
1015
+
1016
+ - **๐Ÿ“– Complete Guide**: [GUIDE.md](./GUIDE.md) - Comprehensive usage guide with best practices
1017
+ - **๐Ÿ“š Documentation**: Check the [docs](./docs) directory for detailed guides
1018
+ - **๐Ÿ› Issues**: [GitHub Issues](https://github.com/mulverse/mulguard/issues)
1019
+ - **๐Ÿ’ฌ Discussions**: [GitHub Discussions](https://github.com/mulverse/mulguard/discussions)
1020
+
1021
+ ## ๐ŸŽฏ Key Features & Improvements
1022
+
1023
+ ### โœจ Latest Updates
1024
+
1025
+ - **โœ… Unified Sign-In Interface** - Use `auth.signIn('credentials', {...})` or `auth.signIn.email({...})`
1026
+ - **โœ… Automatic Input Validation** - Built-in email, password, and provider validation
1027
+ - **โœ… Enhanced Security** - Generic error messages, security logging, XSS/Injection prevention
1028
+ - **โœ… Single Unified Logic** - All sign-in methods use the same core logic
1029
+ - **โœ… Type-Safe** - Full TypeScript support with proper typing
1030
+ - **โœ… Production Ready** - Best practices built-in by default
1031
+
1032
+ ---
359
1033
 
360
- Contributions are welcome! Please read our contributing guidelines first.
1034
+ ## ๐ŸŒŸ About Mulverse
361
1035
 
362
- ## ๐Ÿ“ง Support
1036
+ **Mulguard** is part of the **Mulverse** ecosystem - a collection of modern, developer-friendly libraries and tools for building next-generation web applications.
363
1037
 
364
- For questions and support, please open an issue on GitHub.
1038
+ Visit [mulverse.com](https://mulverse.com) to learn more about our other projects.
365
1039
 
366
1040
  ---
367
1041
 
368
- Made with โค๏ธ by the Mukey Team
1042
+ **Made with โค๏ธ by the Mulverse Team**