@lenne.tech/nest-server 11.10.2 → 11.10.4

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.
Files changed (67) hide show
  1. package/dist/config.env.js +16 -133
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/interfaces/server-options.interface.d.ts +4 -0
  4. package/dist/core/modules/auth/core-auth.module.js +8 -4
  5. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  6. package/dist/core/modules/auth/guards/roles-guard-registry.d.ts +9 -0
  7. package/dist/core/modules/auth/guards/roles-guard-registry.js +30 -0
  8. package/dist/core/modules/auth/guards/roles-guard-registry.js.map +1 -0
  9. package/dist/core/modules/better-auth/better-auth.config.d.ts +3 -0
  10. package/dist/core/modules/better-auth/better-auth.config.js +176 -47
  11. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  12. package/dist/core/modules/better-auth/core-better-auth-api.middleware.d.ts +5 -1
  13. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js +101 -8
  14. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js.map +1 -1
  15. package/dist/core/modules/better-auth/core-better-auth-challenge.service.d.ts +20 -0
  16. package/dist/core/modules/better-auth/core-better-auth-challenge.service.js +142 -0
  17. package/dist/core/modules/better-auth/core-better-auth-challenge.service.js.map +1 -0
  18. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js +1 -1
  19. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -1
  20. package/dist/core/modules/better-auth/core-better-auth-web.helper.d.ts +2 -0
  21. package/dist/core/modules/better-auth/core-better-auth-web.helper.js +29 -1
  22. package/dist/core/modules/better-auth/core-better-auth-web.helper.js.map +1 -1
  23. package/dist/core/modules/better-auth/core-better-auth.controller.js +5 -13
  24. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
  25. package/dist/core/modules/better-auth/core-better-auth.middleware.d.ts +0 -1
  26. package/dist/core/modules/better-auth/core-better-auth.middleware.js +6 -19
  27. package/dist/core/modules/better-auth/core-better-auth.middleware.js.map +1 -1
  28. package/dist/core/modules/better-auth/core-better-auth.module.d.ts +5 -1
  29. package/dist/core/modules/better-auth/core-better-auth.module.js +74 -27
  30. package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
  31. package/dist/core/modules/better-auth/core-better-auth.resolver.js +7 -6
  32. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
  33. package/dist/core/modules/better-auth/core-better-auth.service.d.ts +0 -2
  34. package/dist/core/modules/better-auth/core-better-auth.service.js +23 -37
  35. package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
  36. package/dist/core.module.js +10 -1
  37. package/dist/core.module.js.map +1 -1
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +1 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/server/modules/better-auth/better-auth.module.d.ts +4 -1
  42. package/dist/server/modules/better-auth/better-auth.module.js +4 -1
  43. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
  44. package/dist/server/server.module.js +1 -4
  45. package/dist/server/server.module.js.map +1 -1
  46. package/dist/tsconfig.build.tsbuildinfo +1 -1
  47. package/package.json +1 -1
  48. package/src/config.env.ts +24 -174
  49. package/src/core/common/interfaces/server-options.interface.ts +288 -35
  50. package/src/core/modules/auth/core-auth.module.ts +11 -5
  51. package/src/core/modules/auth/guards/roles-guard-registry.ts +57 -0
  52. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +85 -56
  53. package/src/core/modules/better-auth/README.md +132 -35
  54. package/src/core/modules/better-auth/better-auth.config.ts +402 -70
  55. package/src/core/modules/better-auth/core-better-auth-api.middleware.ts +158 -18
  56. package/src/core/modules/better-auth/core-better-auth-challenge.service.ts +254 -0
  57. package/src/core/modules/better-auth/core-better-auth-user.mapper.ts +1 -1
  58. package/src/core/modules/better-auth/core-better-auth-web.helper.ts +64 -1
  59. package/src/core/modules/better-auth/core-better-auth.controller.ts +6 -14
  60. package/src/core/modules/better-auth/core-better-auth.middleware.ts +7 -20
  61. package/src/core/modules/better-auth/core-better-auth.module.ts +173 -38
  62. package/src/core/modules/better-auth/core-better-auth.resolver.ts +7 -6
  63. package/src/core/modules/better-auth/core-better-auth.service.ts +27 -48
  64. package/src/core.module.ts +21 -3
  65. package/src/index.ts +1 -0
  66. package/src/server/modules/better-auth/better-auth.module.ts +40 -10
  67. package/src/server/server.module.ts +2 -4
@@ -101,6 +101,7 @@ The `CoreBetterAuthUserMapper` enables bidirectional password synchronization:
101
101
  BetterAuthModule.forRoot({
102
102
  config: envConfig.betterAuth,
103
103
  fallbackSecrets: [envConfig.jwt?.secret],
104
+ // registerRolesGuardGlobally defaults to true - @Roles() decorators work automatically!
104
105
  }),
105
106
  // ... other modules
106
107
  ],
@@ -108,6 +109,8 @@ The `CoreBetterAuthUserMapper` enables bidirectional password synchronization:
108
109
  export class ServerModule {}
109
110
  ```
110
111
 
112
+ **Note:** Since 11.10.3, `registerRolesGuardGlobally` defaults to `true`. You don't need to set it explicitly.
113
+
111
114
  #### For Existing Projects (Migration):
112
115
  ```typescript
113
116
  @Module({
@@ -129,38 +132,47 @@ export class ServerModule {}
129
132
  **Modify:** `src/config.env.ts`
130
133
  **Reference:** `node_modules/@lenne.tech/nest-server/src/config.env.ts`
131
134
 
132
- #### For New Projects (IAM-Only):
135
+ #### Zero-Config (Default):
136
+ BetterAuth is **enabled by default** with JWT + 2FA. No configuration required!
137
+
133
138
  ```typescript
134
139
  const config = {
135
- // Disable Legacy Auth endpoints
140
+ // BetterAuth is automatically enabled with:
141
+ // - JWT tokens (for API clients)
142
+ // - 2FA/TOTP (users can enable it in settings)
143
+ // No betterAuth config needed!
144
+
145
+ // For new projects, disable Legacy Auth:
136
146
  auth: {
137
147
  legacyEndpoints: {
138
148
  enabled: false,
139
149
  },
140
150
  },
141
- // BetterAuth configuration (minimal - JWT enabled by default)
142
- betterAuth: true, // or betterAuth: {} for same effect
151
+ };
152
+ ```
143
153
 
144
- // OR with optional features:
145
- betterAuth: {
146
- twoFactor: {}, // Enable 2FA (opt-in)
147
- passkey: {}, // Enable Passkeys (opt-in)
148
- // JWT is already enabled by default
149
- },
154
+ #### With Passkey (auto-detected from baseUrl):
155
+ ```typescript
156
+ const config = {
157
+ // Passkey is auto-activated when URLs can be resolved
158
+ // Option 1: Set root-level baseUrl (production)
159
+ baseUrl: 'https://api.example.com', // rpId, origin, trustedOrigins auto-detected
160
+ env: 'production',
161
+
162
+ // Option 2: Use env: 'local'/'ci'/'e2e' (development)
163
+ // env: 'local', // Uses localhost defaults: API=:3000, App=:3001
150
164
  };
151
165
  ```
152
166
 
153
- #### For Existing Projects (Migration):
167
+ #### Disabling Features:
154
168
  ```typescript
155
169
  const config = {
156
- // Keep Legacy Auth endpoints enabled during migration
157
- auth: {
158
- legacyEndpoints: {
159
- enabled: true, // Default - can disable after migration
160
- },
170
+ betterAuth: {
171
+ jwt: false, // Disable JWT (use cookies only)
172
+ twoFactor: false, // Disable 2FA
161
173
  },
162
- // BetterAuth configuration (JWT enabled by default)
163
- betterAuth: true, // Minimal config, or use object for more options
174
+ // OR disable BetterAuth completely:
175
+ betterAuth: false,
164
176
  };
165
177
  ```
166
178
 
@@ -345,26 +357,31 @@ async function useBackupCode(code: string) {
345
357
 
346
358
  ### Passkey Login Flow (Client-Side)
347
359
 
348
- Handle passkey authentication with session validation fallback:
360
+ Handle passkey authentication with session validation fallback.
361
+
362
+ **IMPORTANT:** For JWT mode (`cookies: false`), you MUST use the `authenticateWithPasskey()` function from the composable instead of `authClient.signIn.passkey()` directly. This is because JWT mode requires sending a `challengeId` to the server for challenge verification.
349
363
 
350
364
  ```typescript
351
- // login.vue - Passkey login
365
+ // login.vue - Passkey login (JWT-compatible)
366
+ // Use authenticateWithPasskey from useBetterAuth composable
367
+ const { authenticateWithPasskey, setUser, validateSession } = useBetterAuth();
368
+
352
369
  async function onPasskeyLogin() {
353
370
  try {
354
- // Use official Better Auth passkey sign-in
355
- const result = await authClient.signIn.passkey();
371
+ // Use composable method which handles challengeId for JWT mode
372
+ const result = await authenticateWithPasskey();
356
373
 
357
- if (result.error) {
358
- showError(result.error.message || 'Passkey authentication failed');
374
+ // Check for error (returns { success, error?, user?, session? })
375
+ if (!result.success) {
376
+ showError(result.error || 'Passkey authentication failed');
359
377
  return;
360
378
  }
361
379
 
362
380
  // Update auth state with user data if available
363
- if (result.data?.user) {
364
- setUser(result.data.user);
365
- } else if (result.data?.session) {
366
- // IMPORTANT: Passkey auth returns session without user
367
- // Fetch user data via session validation
381
+ if (result.user) {
382
+ setUser(result.user);
383
+ } else {
384
+ // Passkey auth may return success without user - fetch via session validation
368
385
  await validateSession();
369
386
  }
370
387
 
@@ -378,33 +395,36 @@ async function onPasskeyLogin() {
378
395
  showError(err instanceof Error ? err.message : 'Passkey login failed');
379
396
  }
380
397
  }
381
-
382
- // Helper: Validate session and fetch user data
383
- async function validateSession() {
384
- const sessionResult = await authClient.$fetch('/session');
385
- if (sessionResult.user) {
386
- setUser(sessionResult.user);
387
- return true;
388
- }
389
- return false;
390
- }
391
398
  ```
392
399
 
400
+ **Why not use `authClient.signIn.passkey()` directly?**
401
+
402
+ In JWT mode (`cookies: false`), the server stores WebAuthn challenges in the database instead of cookies. The server returns a `challengeId` in the generate-options response, which must be sent back in the verify request. The `authenticateWithPasskey()` composable function handles this automatically.
403
+
404
+ | Mode | Challenge Storage | Client Approach |
405
+ |------|------------------|-----------------|
406
+ | Cookie (`cookies: true` or not set) | Cookie (`better-auth.better-auth-passkey`) | Either approach works |
407
+ | JWT (`cookies: false`) | Database with `challengeId` mapping (auto-enabled) | **Must use composable** |
408
+
409
+ **Note:** Database challenge storage is automatically enabled when `options.cookies: false` is set. No additional configuration is required.
410
+
393
411
  ### Passkey Registration (Client-Side)
394
412
 
395
- Register a new passkey for an authenticated user:
413
+ Register a new passkey for an authenticated user.
414
+
415
+ **IMPORTANT:** For JWT mode (`cookies: false`), you MUST use the `registerPasskey()` function from the composable. This ensures the `challengeId` is correctly sent to the server.
396
416
 
397
417
  ```typescript
398
- // settings.vue - Register new passkey
399
- async function registerPasskey() {
418
+ // settings.vue - Register new passkey (JWT-compatible)
419
+ const { registerPasskey, listPasskeys, deletePasskey } = useBetterAuth();
420
+
421
+ async function onRegisterPasskey() {
400
422
  try {
401
- // This calls generate-register-options verify-registration
402
- const result = await authClient.passkey.addPasskey({
403
- name: 'My Device', // Optional: passkey name
404
- });
423
+ // Use composable method which handles challengeId for JWT mode
424
+ const result = await registerPasskey('My Device'); // Optional name
405
425
 
406
- if (result.error) {
407
- showError(result.error.message);
426
+ if (!result.success) {
427
+ showError(result.error || 'Passkey registration failed');
408
428
  return;
409
429
  }
410
430
 
@@ -420,23 +440,32 @@ async function registerPasskey() {
420
440
  }
421
441
  }
422
442
 
423
- // List user's passkeys
443
+ // List user's passkeys (works in both modes)
424
444
  async function loadPasskeys() {
425
- const result = await authClient.passkey.listUserPasskeys();
426
- if (!result.error) {
427
- passkeys.value = result.data || [];
445
+ const result = await listPasskeys();
446
+ if (result.success) {
447
+ passkeys.value = result.passkeys || [];
428
448
  }
429
449
  }
430
450
 
431
- // Delete a passkey
432
- async function deletePasskey(passkeyId: string) {
433
- const result = await authClient.passkey.deletePasskey({ id: passkeyId });
434
- if (!result.error) {
451
+ // Delete a passkey (works in both modes)
452
+ async function onDeletePasskey(passkeyId: string) {
453
+ const result = await deletePasskey(passkeyId);
454
+ if (result.success) {
435
455
  await loadPasskeys();
436
456
  }
437
457
  }
438
458
  ```
439
459
 
460
+ **Alternative for Cookie mode only:**
461
+
462
+ If you're only using Cookie mode (`cookies: true`), you can use `authClient.passkey` directly:
463
+
464
+ ```typescript
465
+ // Cookie mode ONLY - does NOT work with JWT mode
466
+ const result = await authClient.passkey.addPasskey({ name: 'My Device' });
467
+ ```
468
+
440
469
  ---
441
470
 
442
471
  ## Better-Auth Hooks: Limitations & Warnings
@@ -10,11 +10,15 @@ Integration of the [better-auth](https://better-auth.com) authentication framewo
10
10
  CoreModule.forRoot(envConfig), // IAM-only (new projects)
11
11
  CoreBetterAuthModule.forRoot({ config: envConfig.betterAuth, fallbackSecrets: [envConfig.jwt?.secret] }),
12
12
 
13
- // 3. Configure in config.env.ts (minimal - JWT enabled by default):
14
- betterAuth: true // or betterAuth: {} for same effect
15
-
16
- // With optional features:
17
- betterAuth: { twoFactor: {}, passkey: {} }
13
+ // 3. Configure in config.env.ts (zero-config - enabled by default):
14
+ // BetterAuth is enabled automatically with JWT + 2FA
15
+ // Passkey is auto-activated when URLs can be resolved:
16
+ // - via root-level baseUrl (server-wide)
17
+ // - or env: 'local'/'ci'/'e2e' (uses localhost defaults)
18
+ const config = {
19
+ baseUrl: 'https://api.example.com', // Root-level - Passkey auto-detected from this
20
+ env: 'production',
21
+ }
18
22
  ```
19
23
 
20
24
  **Quick Links:** [Integration Checklist](./INTEGRATION-CHECKLIST.md) | [REST API](#rest-api-endpoints) | [GraphQL API](#graphql-api) | [Configuration](#configuration)
@@ -42,8 +46,8 @@ betterAuth: { twoFactor: {}, passkey: {} }
42
46
  ### Built-in Plugins
43
47
 
44
48
  - **JWT Tokens** - For API clients and stateless authentication (**enabled by default**)
45
- - **Two-Factor Authentication (2FA)** - TOTP-based second factor (opt-in)
46
- - **Passkey/WebAuthn** - Passwordless authentication (opt-in)
49
+ - **Two-Factor Authentication (2FA)** - TOTP-based second factor (**enabled by default**)
50
+ - **Passkey/WebAuthn** - Passwordless authentication (**enabled by default**, requires resolvable URLs)
47
51
 
48
52
  ### Core Features
49
53
 
@@ -166,10 +170,11 @@ betterAuth: { enabled: false } // Disable (allows pre-configuration)
166
170
  **Default values (used when not configured):**
167
171
 
168
172
  - **JWT**: Enabled by default
173
+ - **2FA/TOTP**: Enabled by default (users can optionally set up 2FA)
174
+ - **Passkey**: Enabled by default (requires resolvable URLs via `baseUrl`, `appUrl`, or `env: 'local'`)
169
175
  - **Secret**: Falls back to `jwt.secret` → `jwt.refresh.secret` → auto-generated
170
176
  - **Base URL**: `http://localhost:3000`
171
177
  - **Base Path**: `/iam`
172
- - **2FA/Passkey**: Disabled (opt-in)
173
178
 
174
179
  To **explicitly disable** Better-Auth:
175
180
 
@@ -242,18 +247,55 @@ Read the security section below for production deployments.
242
247
 
243
248
  **For Development:** The defaults (`http://localhost:3000`, `/iam`) are correct.
244
249
 
245
- **For Production:** You must set `baseUrl` and `passkey.origin` to your actual domain:
250
+ ### Passkey Auto-Detection (Recommended)
251
+
252
+ **New in v11.x:** Passkey configuration can be auto-detected from URLs:
246
253
 
247
254
  ```typescript
255
+ // RECOMMENDED: Set root-level baseUrl - Passkey values are auto-detected
248
256
  const config = {
257
+ baseUrl: process.env.BASE_URL, // e.g., 'https://api.example.com'
258
+ env: 'production',
259
+ // Passkey is AUTO-ACTIVATED with:
260
+ // - rpId: 'example.com' (derived from appUrl)
261
+ // - origin: 'https://example.com' (= appUrl, derived from baseUrl)
262
+ // - trustedOrigins: ['https://example.com'] (= appUrl)
263
+ };
264
+
265
+ // OR for local development - env: 'local' uses localhost defaults:
266
+ const localConfig = {
267
+ env: 'local', // Uses API=localhost:3000, App=localhost:3001
268
+ };
269
+ ```
270
+
271
+ **Benefits:**
272
+ - **One config per stage**: Only set `BASE_URL` in your environment
273
+ - **No duplication**: Passkey values derived automatically
274
+ - **Graceful Degradation**: If auto-detection fails (no baseUrl), Passkey is disabled with a warning - other auth methods (Email/Password, 2FA) continue to work
275
+
276
+ **Auto-Detection Resolution:**
277
+ | Value | Priority | Source |
278
+ |-------|----------|--------|
279
+ | `baseUrl` | 1. Explicit `betterAuth.baseUrl` → 2. Root-level `baseUrl` → 3. Localhost default (env: 'local') |
280
+ | `appUrl` | 1. Root-level `appUrl` → 2. Derived from `baseUrl` (removes `api.` prefix) → 3. Localhost default |
281
+ | `rpId` | 1. Explicit `passkey.rpId` → 2. Auto-detect from appUrl hostname |
282
+ | `origin` | 1. Explicit `passkey.origin` → 2. Auto-detect from appUrl |
283
+ | `trustedOrigins` | 1. Explicit `trustedOrigins` → 2. Auto-detect from appUrl |
284
+
285
+ ### Explicit Passkey Configuration (Advanced)
286
+
287
+ For production scenarios where you need full control:
288
+
289
+ ```typescript
290
+ const config = {
291
+ baseUrl: 'https://api.your-domain.com', // Root-level
249
292
  betterAuth: {
250
- baseUrl: 'https://api.your-domain.com',
251
293
  passkey: {
252
- // enabled by default when config block is present
253
- origin: 'https://your-domain.com', // Frontend domain
294
+ origin: 'https://your-domain.com', // Frontend domain (if different from API)
254
295
  rpId: 'your-domain.com', // Domain without protocol
255
296
  rpName: 'Your Application',
256
297
  },
298
+ trustedOrigins: ['https://your-domain.com', 'https://admin.your-domain.com'],
257
299
  },
258
300
  };
259
301
  ```
@@ -334,7 +376,53 @@ const config = {
334
376
 
335
377
  ## Configuration
336
378
 
337
- **Optional** - Better-Auth works without any configuration (true zero-config). Only add this block if you need to customize behavior:
379
+ **Optional** - Better-Auth works without any configuration (true zero-config). Only add this block if you need to customize behavior.
380
+
381
+ ### Default Behavior Overview
382
+
383
+ The following table shows which features are active based on your configuration:
384
+
385
+ | Configuration | BetterAuth | JWT | 2FA | Passkey |
386
+ |---------------|:----------:|:---:|:---:|:-------:|
387
+ | *not set* (no URLs) | ✅ | ✅ | ✅ | ⚠️ disabled |
388
+ | `env: 'local'/'ci'/'e2e'` (auto URLs) | ✅ | ✅ | ✅ | ✅ auto |
389
+ | `baseUrl` set | ✅ | ✅ | ✅ | ✅ auto |
390
+ | `betterAuth: false` | ❌ | ❌ | ❌ | ❌ |
391
+ | `{ passkey: false }` | ✅ | ✅ | ✅ | ❌ |
392
+ | `{ twoFactor: false }` | ✅ | ✅ | ❌ | ✅ auto |
393
+
394
+ **Key points:**
395
+ - **BetterAuth** is enabled by default (zero-config)
396
+ - **JWT** is enabled by default (stateless authentication)
397
+ - **2FA/TOTP** is enabled by default (users can optionally set up 2FA)
398
+ - **Passkey/WebAuthn** is enabled by default, but requires resolvable URLs:
399
+ - Explicitly: `passkey.rpId`, `passkey.origin`, `trustedOrigins`
400
+ - Or via `baseUrl` → auto-detects `appUrl`, `rpId`, `origin`, `trustedOrigins`
401
+ - Or via `env: 'local'/'ci'/'e2e'` → uses localhost defaults
402
+
403
+ ### URL Configuration (Important for Passkey!)
404
+
405
+ **Typical Architecture:**
406
+ - **API**: `https://api.example.com` (NestJS server)
407
+ - **App**: `https://example.com` (Frontend where browser runs)
408
+
409
+ **URL Resolution:**
410
+
411
+ | Config | `baseUrl` (API) | `appUrl` (Frontend) | Passkey |
412
+ |--------|-----------------|---------------------|---------|
413
+ | `env: 'local'/'ci'/'e2e'` | `http://localhost:3000` | `http://localhost:3001` | ✅ auto |
414
+ | `baseUrl: 'https://api.example.com'` | as set | `https://example.com` (auto-derived) | ✅ auto |
415
+ | `baseUrl: 'https://example.com'` | as set | `https://example.com` (same) | ✅ auto |
416
+ | `appUrl: 'https://app.example.com'` | - | as set | ✅ auto |
417
+ | Neither set | - | - | ⚠️ disabled |
418
+
419
+ **Auto-Detection Logic:**
420
+ 1. `appUrl` is derived from `baseUrl` by removing `api.` prefix
421
+ 2. `rpId` is extracted from `appUrl` (e.g., `example.com`)
422
+ 3. `origin` = `appUrl` (e.g., `https://example.com`)
423
+ 4. `trustedOrigins` = `[appUrl]` (e.g., `['https://example.com']`)
424
+
425
+ ### Configuration Examples
338
426
 
339
427
  ```typescript
340
428
  // In config.env.ts
@@ -358,17 +446,23 @@ export default {
358
446
  // enabled: false, // Uncomment to disable JWT
359
447
  },
360
448
 
361
- // Two-Factor Authentication (opt-in - requires config block)
449
+ // Two-Factor Authentication - ENABLED BY DEFAULT
450
+ // Only add this block to customize or explicitly disable
362
451
  twoFactor: {
363
- appName: 'My Application',
452
+ appName: 'My Application', // Default: 'Nest Server'
453
+ // enabled: false, // Uncomment to disable 2FA
364
454
  },
365
455
 
366
- // Passkey/WebAuthn (opt-in - requires config block)
367
- passkey: {
368
- rpId: 'localhost',
369
- rpName: 'My Application',
370
- origin: 'http://localhost:3000',
371
- },
456
+ // Passkey/WebAuthn - Auto-detection from baseUrl!
457
+ // If baseUrl is set, rpId/origin/trustedOrigins are auto-detected
458
+ passkey: true, // Just enable - values derived from baseUrl
459
+
460
+ // OR with explicit configuration (overrides auto-detection):
461
+ // passkey: {
462
+ // rpId: 'localhost', // Auto-detected from baseUrl hostname
463
+ // rpName: 'My Application',
464
+ // origin: 'http://localhost:3000', // Auto-detected from baseUrl
465
+ // },
372
466
 
373
467
  // Social Providers (enabled by default when credentials are configured)
374
468
  // Set enabled: false to explicitly disable a provider
@@ -384,6 +478,8 @@ export default {
384
478
  },
385
479
 
386
480
  // Trusted Origins for CORS
481
+ // Auto-detected from baseUrl when Passkey is enabled!
482
+ // Only set explicitly if you need additional origins
387
483
  trustedOrigins: ['http://localhost:3000', 'https://your-app.com'],
388
484
 
389
485
  // Rate Limiting (optional)
@@ -529,26 +625,27 @@ Better-Auth provides a rich plugin ecosystem. This module uses a **hybrid approa
529
625
 
530
626
  ### Built-in Plugins
531
627
 
532
- | Plugin | Default State | Minimal Config to Enable | Default Values |
628
+ | Plugin | Default State | Config to Disable | Default Values |
533
629
  | ------------------ | ------------- | ------------------------ | --------------------------------------------------------------------------------- |
534
- | **JWT** | **ENABLED** | *(none needed)* | `expiresIn: '15m'` |
535
- | **Two-Factor** | Disabled | `twoFactor: {}` | `appName: 'Nest Server'` |
536
- | **Passkey** | Disabled | `passkey: {}` | `origin: 'http://localhost:3000'`, `rpId: 'localhost'`, `rpName: 'Nest Server'` |
630
+ | **JWT** | **ENABLED** | `jwt: false` | `expiresIn: '15m'` |
631
+ | **Two-Factor** | **ENABLED** | `twoFactor: false` | `appName: 'Nest Server'` |
632
+ | **Passkey** | **ENABLED** | `passkey: false` | Auto-detected from `baseUrl`/`appUrl`, `rpName: 'Nest Server'` |
537
633
 
538
- **JWT is enabled by default** - no configuration needed. 2FA and Passkey require explicit configuration.
634
+ **All three plugins are enabled by default** - no configuration needed. Passkey requires resolvable URLs to function (via `baseUrl`, `appUrl`, or `env: 'local'/'ci'/'e2e'`). If URLs cannot be resolved, Passkey is disabled with a warning (graceful degradation).
539
635
 
540
636
  #### Minimal Syntax (Recommended for Development)
541
637
 
542
638
  ```typescript
543
639
  const config = {
544
- // JWT is enabled automatically with BetterAuth
640
+ // JWT and 2FA are enabled automatically with BetterAuth
545
641
  betterAuth: true, // or betterAuth: {}
546
642
 
547
- // To also enable 2FA and Passkey:
548
- betterAuth: {
549
- twoFactor: {},
550
- passkey: {},
551
- },
643
+ // Passkey is auto-activated when URLs can be resolved:
644
+ // Option 1: Set root-level baseUrl (production)
645
+ baseUrl: 'https://api.example.com', // Passkey values auto-detected from this
646
+
647
+ // Option 2: Use env: 'local'/'ci'/'e2e' (development)
648
+ env: 'local', // Uses localhost defaults: API=:3000, App=:3001
552
649
  };
553
650
  ```
554
651
 
@@ -574,13 +671,13 @@ const config = {
574
671
  const config = {
575
672
  betterAuth: {
576
673
  jwt: false, // Disable JWT (or jwt: { enabled: false })
577
- twoFactor: {}, // 2FA enabled with defaults
578
- passkey: { enabled: false }, // Passkey explicitly disabled
674
+ twoFactor: false, // Disable 2FA (or twoFactor: { enabled: false })
675
+ passkey: false, // Disable Passkey (or passkey: { enabled: false })
579
676
  },
580
677
  };
581
678
  ```
582
679
 
583
- **Note:** JWT is the only plugin enabled by default. To disable it, use `jwt: false` or `jwt: { enabled: false }`.
680
+ **Note:** All three plugins (JWT, 2FA, Passkey) are enabled by default. Passkey requires resolvable URLs to function. Use `false` or `{ enabled: false }` to disable any plugin.
584
681
 
585
682
  ### Dynamic Plugins (plugins Array)
586
683