@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.
- package/dist/config.env.js +16 -133
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +4 -0
- package/dist/core/modules/auth/core-auth.module.js +8 -4
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/guards/roles-guard-registry.d.ts +9 -0
- package/dist/core/modules/auth/guards/roles-guard-registry.js +30 -0
- package/dist/core/modules/auth/guards/roles-guard-registry.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.config.d.ts +3 -0
- package/dist/core/modules/better-auth/better-auth.config.js +176 -47
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-api.middleware.d.ts +5 -1
- package/dist/core/modules/better-auth/core-better-auth-api.middleware.js +101 -8
- package/dist/core/modules/better-auth/core-better-auth-api.middleware.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-challenge.service.d.ts +20 -0
- package/dist/core/modules/better-auth/core-better-auth-challenge.service.js +142 -0
- package/dist/core/modules/better-auth/core-better-auth-challenge.service.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.js +1 -1
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-web.helper.d.ts +2 -0
- package/dist/core/modules/better-auth/core-better-auth-web.helper.js +29 -1
- package/dist/core/modules/better-auth/core-better-auth-web.helper.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.controller.js +5 -13
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.middleware.d.ts +0 -1
- package/dist/core/modules/better-auth/core-better-auth.middleware.js +6 -19
- package/dist/core/modules/better-auth/core-better-auth.middleware.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.module.d.ts +5 -1
- package/dist/core/modules/better-auth/core-better-auth.module.js +74 -27
- package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.resolver.js +7 -6
- package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.service.d.ts +0 -2
- package/dist/core/modules/better-auth/core-better-auth.service.js +23 -37
- package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
- package/dist/core.module.js +10 -1
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/better-auth/better-auth.module.d.ts +4 -1
- package/dist/server/modules/better-auth/better-auth.module.js +4 -1
- package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
- package/dist/server/server.module.js +1 -4
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config.env.ts +24 -174
- package/src/core/common/interfaces/server-options.interface.ts +288 -35
- package/src/core/modules/auth/core-auth.module.ts +11 -5
- package/src/core/modules/auth/guards/roles-guard-registry.ts +57 -0
- package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +85 -56
- package/src/core/modules/better-auth/README.md +132 -35
- package/src/core/modules/better-auth/better-auth.config.ts +402 -70
- package/src/core/modules/better-auth/core-better-auth-api.middleware.ts +158 -18
- package/src/core/modules/better-auth/core-better-auth-challenge.service.ts +254 -0
- package/src/core/modules/better-auth/core-better-auth-user.mapper.ts +1 -1
- package/src/core/modules/better-auth/core-better-auth-web.helper.ts +64 -1
- package/src/core/modules/better-auth/core-better-auth.controller.ts +6 -14
- package/src/core/modules/better-auth/core-better-auth.middleware.ts +7 -20
- package/src/core/modules/better-auth/core-better-auth.module.ts +173 -38
- package/src/core/modules/better-auth/core-better-auth.resolver.ts +7 -6
- package/src/core/modules/better-auth/core-better-auth.service.ts +27 -48
- package/src/core.module.ts +21 -3
- package/src/index.ts +1 -0
- package/src/server/modules/better-auth/better-auth.module.ts +40 -10
- 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
|
-
####
|
|
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
|
-
//
|
|
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
|
-
|
|
142
|
-
|
|
151
|
+
};
|
|
152
|
+
```
|
|
143
153
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
####
|
|
167
|
+
#### Disabling Features:
|
|
154
168
|
```typescript
|
|
155
169
|
const config = {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
//
|
|
163
|
-
betterAuth:
|
|
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
|
|
355
|
-
const result = await
|
|
371
|
+
// Use composable method which handles challengeId for JWT mode
|
|
372
|
+
const result = await authenticateWithPasskey();
|
|
356
373
|
|
|
357
|
-
|
|
358
|
-
|
|
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.
|
|
364
|
-
setUser(result.
|
|
365
|
-
} else
|
|
366
|
-
//
|
|
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
|
-
|
|
418
|
+
// settings.vue - Register new passkey (JWT-compatible)
|
|
419
|
+
const { registerPasskey, listPasskeys, deletePasskey } = useBetterAuth();
|
|
420
|
+
|
|
421
|
+
async function onRegisterPasskey() {
|
|
400
422
|
try {
|
|
401
|
-
//
|
|
402
|
-
const result = await
|
|
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.
|
|
407
|
-
showError(result.error
|
|
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
|
|
426
|
-
if (
|
|
427
|
-
passkeys.value = result.
|
|
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
|
|
433
|
-
const result = await
|
|
434
|
-
if (
|
|
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 (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
//
|
|
17
|
-
|
|
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 (
|
|
46
|
-
- **Passkey/WebAuthn** - Passwordless authentication (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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 |
|
|
628
|
+
| Plugin | Default State | Config to Disable | Default Values |
|
|
533
629
|
| ------------------ | ------------- | ------------------------ | --------------------------------------------------------------------------------- |
|
|
534
|
-
| **JWT** | **ENABLED** |
|
|
535
|
-
| **Two-Factor** |
|
|
536
|
-
| **Passkey** |
|
|
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
|
-
**
|
|
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
|
|
640
|
+
// JWT and 2FA are enabled automatically with BetterAuth
|
|
545
641
|
betterAuth: true, // or betterAuth: {}
|
|
546
642
|
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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:
|
|
578
|
-
passkey: { enabled: false }
|
|
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
|
|
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
|
|