@better-auth/core 1.4.0-beta.7 → 1.4.0-beta.9

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 (124) hide show
  1. package/.turbo/turbo-build.log +54 -4
  2. package/build.config.ts +6 -0
  3. package/dist/db/adapter/index.d.cts +14 -23
  4. package/dist/db/adapter/index.d.mts +14 -23
  5. package/dist/db/adapter/index.d.ts +14 -23
  6. package/dist/db/index.cjs +16 -0
  7. package/dist/db/index.d.cts +6 -83
  8. package/dist/db/index.d.mts +6 -83
  9. package/dist/db/index.d.ts +6 -83
  10. package/dist/db/index.mjs +16 -1
  11. package/dist/env/index.cjs +315 -0
  12. package/dist/env/index.d.cts +36 -0
  13. package/dist/env/index.d.mts +36 -0
  14. package/dist/env/index.d.ts +36 -0
  15. package/dist/env/index.mjs +300 -0
  16. package/dist/error/index.cjs +44 -0
  17. package/dist/error/index.d.cts +33 -0
  18. package/dist/error/index.d.mts +33 -0
  19. package/dist/error/index.d.ts +33 -0
  20. package/dist/error/index.mjs +41 -0
  21. package/dist/index.d.cts +159 -94
  22. package/dist/index.d.mts +159 -94
  23. package/dist/index.d.ts +159 -94
  24. package/dist/middleware/index.cjs +25 -0
  25. package/dist/middleware/index.d.cts +14 -0
  26. package/dist/middleware/index.d.mts +14 -0
  27. package/dist/middleware/index.d.ts +14 -0
  28. package/dist/middleware/index.mjs +21 -0
  29. package/dist/oauth2/index.cjs +368 -0
  30. package/dist/oauth2/index.d.cts +99 -0
  31. package/dist/oauth2/index.d.mts +99 -0
  32. package/dist/oauth2/index.d.ts +99 -0
  33. package/dist/oauth2/index.mjs +357 -0
  34. package/dist/shared/core.2rWMW9q9.d.ts +13 -0
  35. package/dist/shared/core.40VTWh-p.d.cts +217 -0
  36. package/dist/shared/core.BfcVdsSf.d.cts +181 -0
  37. package/dist/shared/core.Bisb2Bdk.d.mts +181 -0
  38. package/dist/shared/core.BwoNUcJQ.d.cts +53 -0
  39. package/dist/shared/core.BwoNUcJQ.d.mts +53 -0
  40. package/dist/shared/core.BwoNUcJQ.d.ts +53 -0
  41. package/dist/shared/core.CErFRCOZ.d.mts +1684 -0
  42. package/dist/shared/core.CGN6D-Mh.d.ts +181 -0
  43. package/dist/shared/core.CPuIItYE.d.ts +217 -0
  44. package/dist/shared/core.CftpHMDz.d.cts +13 -0
  45. package/dist/shared/core.Db7zJyxf.d.ts +1684 -0
  46. package/dist/shared/core.DqaxObkf.d.cts +1684 -0
  47. package/dist/shared/core.MjcDoj7R.d.cts +5 -0
  48. package/dist/shared/core.MjcDoj7R.d.mts +5 -0
  49. package/dist/shared/core.MjcDoj7R.d.ts +5 -0
  50. package/dist/shared/core.g2ZbxAEV.d.mts +217 -0
  51. package/dist/shared/core.g9ACQ8v2.d.mts +13 -0
  52. package/dist/social-providers/index.cjs +2793 -0
  53. package/dist/social-providers/index.d.cts +3903 -0
  54. package/dist/social-providers/index.d.mts +3903 -0
  55. package/dist/social-providers/index.d.ts +3903 -0
  56. package/dist/social-providers/index.mjs +2743 -0
  57. package/dist/utils/index.cjs +7 -0
  58. package/dist/utils/index.d.cts +10 -0
  59. package/dist/utils/index.d.mts +10 -0
  60. package/dist/utils/index.d.ts +10 -0
  61. package/dist/utils/index.mjs +5 -0
  62. package/package.json +99 -2
  63. package/src/db/adapter/index.ts +424 -0
  64. package/src/db/index.ts +4 -0
  65. package/src/db/schema/rate-limit.ts +21 -0
  66. package/src/db/type.ts +29 -10
  67. package/src/env/color-depth.ts +171 -0
  68. package/src/env/env-impl.ts +123 -0
  69. package/src/env/index.ts +23 -0
  70. package/src/env/logger.test.ts +33 -0
  71. package/src/env/logger.ts +145 -0
  72. package/src/error/codes.ts +31 -0
  73. package/src/error/index.ts +11 -0
  74. package/src/index.ts +0 -2
  75. package/src/middleware/index.ts +33 -0
  76. package/src/oauth2/client-credentials-token.ts +102 -0
  77. package/src/oauth2/create-authorization-url.ts +85 -0
  78. package/src/oauth2/index.ts +22 -0
  79. package/src/oauth2/oauth-provider.ts +194 -0
  80. package/src/oauth2/refresh-access-token.ts +124 -0
  81. package/src/oauth2/utils.ts +36 -0
  82. package/src/oauth2/validate-authorization-code.ts +156 -0
  83. package/src/social-providers/apple.ts +213 -0
  84. package/src/social-providers/atlassian.ts +130 -0
  85. package/src/social-providers/cognito.ts +269 -0
  86. package/src/social-providers/discord.ts +172 -0
  87. package/src/social-providers/dropbox.ts +112 -0
  88. package/src/social-providers/facebook.ts +204 -0
  89. package/src/social-providers/figma.ts +115 -0
  90. package/src/social-providers/github.ts +154 -0
  91. package/src/social-providers/gitlab.ts +152 -0
  92. package/src/social-providers/google.ts +171 -0
  93. package/src/social-providers/huggingface.ts +116 -0
  94. package/src/social-providers/index.ts +118 -0
  95. package/src/social-providers/kakao.ts +178 -0
  96. package/src/social-providers/kick.ts +95 -0
  97. package/src/social-providers/line.ts +169 -0
  98. package/src/social-providers/linear.ts +120 -0
  99. package/src/social-providers/linkedin.ts +110 -0
  100. package/src/social-providers/microsoft-entra-id.ts +243 -0
  101. package/src/social-providers/naver.ts +112 -0
  102. package/src/social-providers/notion.ts +106 -0
  103. package/src/social-providers/paypal.ts +261 -0
  104. package/src/social-providers/reddit.ts +122 -0
  105. package/src/social-providers/roblox.ts +110 -0
  106. package/src/social-providers/salesforce.ts +157 -0
  107. package/src/social-providers/slack.ts +114 -0
  108. package/src/social-providers/spotify.ts +93 -0
  109. package/src/social-providers/tiktok.ts +211 -0
  110. package/src/social-providers/twitch.ts +111 -0
  111. package/src/social-providers/twitter.ts +194 -0
  112. package/src/social-providers/vk.ts +128 -0
  113. package/src/social-providers/zoom.ts +218 -0
  114. package/src/types/context.ts +270 -0
  115. package/src/types/cookie.ts +7 -0
  116. package/src/types/index.ts +19 -1
  117. package/src/types/init-options.ts +1039 -2
  118. package/src/types/plugin-client.ts +69 -0
  119. package/src/types/plugin.ts +134 -0
  120. package/src/utils/error-codes.ts +51 -0
  121. package/src/utils/index.ts +1 -0
  122. package/dist/shared/core.CnvFgghY.d.cts +0 -117
  123. package/dist/shared/core.CnvFgghY.d.mts +0 -117
  124. package/dist/shared/core.CnvFgghY.d.ts +0 -117
@@ -1,12 +1,110 @@
1
+ import type { Dialect, Kysely, MysqlPool, PostgresPool } from "kysely";
2
+ import type { Database } from "better-sqlite3";
1
3
  import type { CookieOptions } from "better-call";
2
4
  import type { LiteralUnion } from "./helper";
3
- import type { Models } from "../db/type";
5
+ import type {
6
+ DBFieldAttribute,
7
+ DBPreservedModels,
8
+ SecondaryStorage,
9
+ } from "../db/type";
10
+ import type { Account, RateLimit, Session, User, Verification } from "../db";
11
+ import type { Database as BunDatabase } from "bun:sqlite";
12
+ import type { DatabaseSync } from "node:sqlite";
13
+ import type { DBAdapterDebugLogOption, DBAdapterInstance } from "../db/adapter";
14
+ import type { SocialProviderList, SocialProviders } from "../social-providers";
15
+ import type { Logger } from "../env";
16
+ import type { AuthContext, GenericEndpointContext } from "./context";
17
+ import type { AuthMiddleware } from "../middleware";
18
+ import type { BetterAuthPlugin } from "@better-auth/core";
19
+
20
+ type KyselyDatabaseType = "postgres" | "mysql" | "sqlite" | "mssql";
21
+ type OmitId<T extends { id: unknown }> = Omit<T, "id">;
4
22
 
5
23
  export type GenerateIdFn = (options: {
6
- model: LiteralUnion<Models, string>;
24
+ model: LiteralUnion<DBPreservedModels, string>;
7
25
  size?: number;
8
26
  }) => string | false;
9
27
 
28
+ export type BetterAuthRateLimitOptions = {
29
+ /**
30
+ * By default, rate limiting is only
31
+ * enabled on production.
32
+ */
33
+ enabled?: boolean;
34
+ /**
35
+ * Default window to use for rate limiting. The value
36
+ * should be in seconds.
37
+ *
38
+ * @default 10 seconds
39
+ */
40
+ window?: number;
41
+ /**
42
+ * The default maximum number of requests allowed within the window.
43
+ *
44
+ * @default 100 requests
45
+ */
46
+ max?: number;
47
+ /**
48
+ * Custom rate limit rules to apply to
49
+ * specific paths.
50
+ */
51
+ customRules?: {
52
+ [key: string]:
53
+ | {
54
+ /**
55
+ * The window to use for the custom rule.
56
+ */
57
+ window: number;
58
+ /**
59
+ * The maximum number of requests allowed within the window.
60
+ */
61
+ max: number;
62
+ }
63
+ | false
64
+ | ((request: Request) =>
65
+ | { window: number; max: number }
66
+ | false
67
+ | Promise<
68
+ | {
69
+ window: number;
70
+ max: number;
71
+ }
72
+ | false
73
+ >);
74
+ };
75
+ /**
76
+ * Storage configuration
77
+ *
78
+ * By default, rate limiting is stored in memory. If you passed a
79
+ * secondary storage, rate limiting will be stored in the secondary
80
+ * storage.
81
+ *
82
+ * @default "memory"
83
+ */
84
+ storage?: "memory" | "database" | "secondary-storage";
85
+ /**
86
+ * If database is used as storage, the name of the table to
87
+ * use for rate limiting.
88
+ *
89
+ * @default "rateLimit"
90
+ */
91
+ modelName?: string;
92
+ /**
93
+ * Custom field names for the rate limit table
94
+ */
95
+ fields?: Record<keyof RateLimit, string>;
96
+ /**
97
+ * custom storage configuration.
98
+ *
99
+ * NOTE: If custom storage is used storage
100
+ * is ignored
101
+ */
102
+ customStorage?: {
103
+ get: (key: string) => Promise<RateLimit | undefined>;
104
+ set: (key: string, value: RateLimit) => Promise<void>;
105
+ };
106
+ };
107
+
10
108
  export type BetterAuthAdvancedOptions = {
11
109
  /**
12
110
  * Ip address configuration
@@ -117,3 +215,942 @@ export type BetterAuthAdvancedOptions = {
117
215
  generateId?: GenerateIdFn | false;
118
216
  };
119
217
  };
218
+
219
+ export type BetterAuthOptions = {
220
+ /**
221
+ * The name of the application
222
+ *
223
+ * process.env.APP_NAME
224
+ *
225
+ * @default "Better Auth"
226
+ */
227
+ appName?: string;
228
+ /**
229
+ * Base URL for the Better Auth. This is typically the
230
+ * root URL where your application server is hosted.
231
+ * If not explicitly set,
232
+ * the system will check the following environment variable:
233
+ *
234
+ * process.env.BETTER_AUTH_URL
235
+ */
236
+ baseURL?: string;
237
+ /**
238
+ * Base path for the Better Auth. This is typically
239
+ * the path where the
240
+ * Better Auth routes are mounted.
241
+ *
242
+ * @default "/api/auth"
243
+ */
244
+ basePath?: string;
245
+ /**
246
+ * The secret to use for encryption,
247
+ * signing and hashing.
248
+ *
249
+ * By default Better Auth will look for
250
+ * the following environment variables:
251
+ * process.env.BETTER_AUTH_SECRET,
252
+ * process.env.AUTH_SECRET
253
+ * If none of these environment
254
+ * variables are set,
255
+ * it will default to
256
+ * "better-auth-secret-123456789".
257
+ *
258
+ * on production if it's not set
259
+ * it will throw an error.
260
+ *
261
+ * you can generate a good secret
262
+ * using the following command:
263
+ * @example
264
+ * ```bash
265
+ * openssl rand -base64 32
266
+ * ```
267
+ */
268
+ secret?: string;
269
+ /**
270
+ * Database configuration
271
+ */
272
+ database?:
273
+ | PostgresPool
274
+ | MysqlPool
275
+ | Database
276
+ | Dialect
277
+ | DBAdapterInstance
278
+ | BunDatabase
279
+ | DatabaseSync
280
+ | {
281
+ dialect: Dialect;
282
+ type: KyselyDatabaseType;
283
+ /**
284
+ * casing for table names
285
+ *
286
+ * @default "camel"
287
+ */
288
+ casing?: "snake" | "camel";
289
+ /**
290
+ * Enable debug logs for the adapter
291
+ *
292
+ * @default false
293
+ */
294
+ debugLogs?: DBAdapterDebugLogOption;
295
+ /**
296
+ * Whether to execute multiple operations in a transaction.
297
+ * If the database doesn't support transactions,
298
+ * set this to `false` and operations will be executed sequentially.
299
+ * @default true
300
+ */
301
+ transaction?: boolean;
302
+ }
303
+ | {
304
+ /**
305
+ * Kysely instance
306
+ */
307
+ db: Kysely<any>;
308
+ /**
309
+ * Database type between postgres, mysql and sqlite
310
+ */
311
+ type: KyselyDatabaseType;
312
+ /**
313
+ * casing for table names
314
+ *
315
+ * @default "camel"
316
+ */
317
+ casing?: "snake" | "camel";
318
+ /**
319
+ * Enable debug logs for the adapter
320
+ *
321
+ * @default false
322
+ */
323
+ debugLogs?: DBAdapterDebugLogOption;
324
+ /**
325
+ * Whether to execute multiple operations in a transaction.
326
+ * If the database doesn't support transactions,
327
+ * set this to `false` and operations will be executed sequentially.
328
+ * @default true
329
+ */
330
+ transaction?: boolean;
331
+ };
332
+ /**
333
+ * Secondary storage configuration
334
+ *
335
+ * This is used to store session and rate limit data.
336
+ */
337
+ secondaryStorage?: SecondaryStorage;
338
+ /**
339
+ * Email verification configuration
340
+ */
341
+ emailVerification?: {
342
+ /**
343
+ * Send a verification email
344
+ * @param data the data object
345
+ * @param request the request object
346
+ */
347
+ sendVerificationEmail?: (
348
+ /**
349
+ * @param user the user to send the
350
+ * verification email to
351
+ * @param url the URL to send the verification email to
352
+ * it contains the token as well
353
+ * @param token the token to send the verification email to
354
+ */
355
+ data: {
356
+ user: User;
357
+ url: string;
358
+ token: string;
359
+ },
360
+ /**
361
+ * The request object
362
+ */
363
+ request?: Request,
364
+ ) => Promise<void>;
365
+ /**
366
+ * Send a verification email automatically
367
+ * after sign up
368
+ *
369
+ * @default false
370
+ */
371
+ sendOnSignUp?: boolean;
372
+ /**
373
+ * Send a verification email automatically
374
+ * on sign in when the user's email is not verified
375
+ *
376
+ * @default false
377
+ */
378
+ sendOnSignIn?: boolean;
379
+ /**
380
+ * Auto signin the user after they verify their email
381
+ */
382
+ autoSignInAfterVerification?: boolean;
383
+ /**
384
+ * Number of seconds the verification token is
385
+ * valid for.
386
+ * @default 3600 seconds (1 hour)
387
+ */
388
+ expiresIn?: number;
389
+ /**
390
+ * A function that is called when a user verifies their email
391
+ * @param user the user that verified their email
392
+ * @param request the request object
393
+ */
394
+ onEmailVerification?: (user: User, request?: Request) => Promise<void>;
395
+ /**
396
+ * A function that is called when a user's email is updated to verified
397
+ * @param user the user that verified their email
398
+ * @param request the request object
399
+ */
400
+ afterEmailVerification?: (user: User, request?: Request) => Promise<void>;
401
+ };
402
+ /**
403
+ * Email and password authentication
404
+ */
405
+ emailAndPassword?: {
406
+ /**
407
+ * Enable email and password authentication
408
+ *
409
+ * @default false
410
+ */
411
+ enabled: boolean;
412
+ /**
413
+ * Disable email and password sign up
414
+ *
415
+ * @default false
416
+ */
417
+ disableSignUp?: boolean;
418
+ /**
419
+ * Require email verification before a session
420
+ * can be created for the user.
421
+ *
422
+ * if the user is not verified, the user will not be able to sign in
423
+ * and on sign in attempts, the user will be prompted to verify their email.
424
+ */
425
+ requireEmailVerification?: boolean;
426
+ /**
427
+ * The maximum length of the password.
428
+ *
429
+ * @default 128
430
+ */
431
+ maxPasswordLength?: number;
432
+ /**
433
+ * The minimum length of the password.
434
+ *
435
+ * @default 8
436
+ */
437
+ minPasswordLength?: number;
438
+ /**
439
+ * send reset password
440
+ */
441
+ sendResetPassword?: (
442
+ /**
443
+ * @param user the user to send the
444
+ * reset password email to
445
+ * @param url the URL to send the reset password email to
446
+ * @param token the token to send to the user (could be used instead of sending the url
447
+ * if you need to redirect the user to custom route)
448
+ */
449
+ data: { user: User; url: string; token: string },
450
+ /**
451
+ * The request object
452
+ */
453
+ request?: Request,
454
+ ) => Promise<void>;
455
+ /**
456
+ * Number of seconds the reset password token is
457
+ * valid for.
458
+ * @default 1 hour (60 * 60)
459
+ */
460
+ resetPasswordTokenExpiresIn?: number;
461
+ /**
462
+ * A callback function that is triggered
463
+ * when a user's password is changed successfully.
464
+ */
465
+ onPasswordReset?: (
466
+ data: { user: User },
467
+ request?: Request,
468
+ ) => Promise<void>;
469
+ /**
470
+ * Password hashing and verification
471
+ *
472
+ * By default Scrypt is used for password hashing and
473
+ * verification. You can provide your own hashing and
474
+ * verification function. if you want to use a
475
+ * different algorithm.
476
+ */
477
+ password?: {
478
+ hash?: (password: string) => Promise<string>;
479
+ verify?: (data: { hash: string; password: string }) => Promise<boolean>;
480
+ };
481
+ /**
482
+ * Automatically sign in the user after sign up
483
+ *
484
+ * @default true
485
+ */
486
+ autoSignIn?: boolean;
487
+ /**
488
+ * Whether to revoke all other sessions when resetting password
489
+ * @default false
490
+ */
491
+ revokeSessionsOnPasswordReset?: boolean;
492
+ };
493
+ /**
494
+ * list of social providers
495
+ */
496
+ socialProviders?: SocialProviders;
497
+ /**
498
+ * List of Better Auth plugins
499
+ */
500
+ plugins?: [] | BetterAuthPlugin[];
501
+ /**
502
+ * User configuration
503
+ */
504
+ user?: {
505
+ /**
506
+ * The model name for the user. Defaults to "user".
507
+ */
508
+ modelName?: string;
509
+ /**
510
+ * Map fields
511
+ *
512
+ * @example
513
+ * ```ts
514
+ * {
515
+ * userId: "user_id"
516
+ * }
517
+ * ```
518
+ */
519
+ fields?: Partial<Record<keyof OmitId<User>, string>>;
520
+ /**
521
+ * Additional fields for the user
522
+ */
523
+ additionalFields?: {
524
+ [key: string]: DBFieldAttribute;
525
+ };
526
+ /**
527
+ * Changing email configuration
528
+ */
529
+ changeEmail?: {
530
+ /**
531
+ * Enable changing email
532
+ * @default false
533
+ */
534
+ enabled: boolean;
535
+ /**
536
+ * Send a verification email when the user changes their email.
537
+ * @param data the data object
538
+ * @param request the request object
539
+ */
540
+ sendChangeEmailVerification?: (
541
+ data: {
542
+ user: User;
543
+ newEmail: string;
544
+ url: string;
545
+ token: string;
546
+ },
547
+ request?: Request,
548
+ ) => Promise<void>;
549
+ };
550
+ /**
551
+ * User deletion configuration
552
+ */
553
+ deleteUser?: {
554
+ /**
555
+ * Enable user deletion
556
+ */
557
+ enabled?: boolean;
558
+ /**
559
+ * Send a verification email when the user deletes their account.
560
+ *
561
+ * if this is not set, the user will be deleted immediately.
562
+ * @param data the data object
563
+ * @param request the request object
564
+ */
565
+ sendDeleteAccountVerification?: (
566
+ data: {
567
+ user: User;
568
+ url: string;
569
+ token: string;
570
+ },
571
+ request?: Request,
572
+ ) => Promise<void>;
573
+ /**
574
+ * A function that is called before a user is deleted.
575
+ *
576
+ * to interrupt with error you can throw `APIError`
577
+ */
578
+ beforeDelete?: (user: User, request?: Request) => Promise<void>;
579
+ /**
580
+ * A function that is called after a user is deleted.
581
+ *
582
+ * This is useful for cleaning up user data
583
+ */
584
+ afterDelete?: (user: User, request?: Request) => Promise<void>;
585
+ /**
586
+ * The expiration time for the delete token.
587
+ *
588
+ * @default 1 day (60 * 60 * 24) in seconds
589
+ */
590
+ deleteTokenExpiresIn?: number;
591
+ };
592
+ };
593
+ session?: {
594
+ /**
595
+ * The model name for the session.
596
+ *
597
+ * @default "session"
598
+ */
599
+ modelName?: string;
600
+ /**
601
+ * Map fields
602
+ *
603
+ * @example
604
+ * ```ts
605
+ * {
606
+ * userId: "user_id"
607
+ * }
608
+ */
609
+ fields?: Partial<Record<keyof OmitId<Session>, string>>;
610
+ /**
611
+ * Expiration time for the session token. The value
612
+ * should be in seconds.
613
+ * @default 7 days (60 * 60 * 24 * 7)
614
+ */
615
+ expiresIn?: number;
616
+ /**
617
+ * How often the session should be refreshed. The value
618
+ * should be in seconds.
619
+ * If set 0 the session will be refreshed every time it is used.
620
+ * @default 1 day (60 * 60 * 24)
621
+ */
622
+ updateAge?: number;
623
+ /**
624
+ * Disable session refresh so that the session is not updated
625
+ * regardless of the `updateAge` option.
626
+ *
627
+ * @default false
628
+ */
629
+ disableSessionRefresh?: boolean;
630
+ /**
631
+ * Additional fields for the session
632
+ */
633
+ additionalFields?: {
634
+ [key: string]: DBFieldAttribute;
635
+ };
636
+ /**
637
+ * By default if secondary storage is provided
638
+ * the session is stored in the secondary storage.
639
+ *
640
+ * Set this to true to store the session in the database
641
+ * as well.
642
+ *
643
+ * Reads are always done from the secondary storage.
644
+ *
645
+ * @default false
646
+ */
647
+ storeSessionInDatabase?: boolean;
648
+ /**
649
+ * By default, sessions are deleted from the database when secondary storage
650
+ * is provided when session is revoked.
651
+ *
652
+ * Set this to true to preserve session records in the database,
653
+ * even if they are deleted from the secondary storage.
654
+ *
655
+ * @default false
656
+ */
657
+ preserveSessionInDatabase?: boolean;
658
+ /**
659
+ * Enable caching session in cookie
660
+ */
661
+ cookieCache?: {
662
+ /**
663
+ * max age of the cookie
664
+ * @default 5 minutes (5 * 60)
665
+ */
666
+ maxAge?: number;
667
+ /**
668
+ * Enable caching session in cookie
669
+ * @default false
670
+ */
671
+ enabled?: boolean;
672
+ };
673
+ /**
674
+ * The age of the session to consider it fresh.
675
+ *
676
+ * This is used to check if the session is fresh
677
+ * for sensitive operations. (e.g. deleting an account)
678
+ *
679
+ * If the session is not fresh, the user should be prompted
680
+ * to sign in again.
681
+ *
682
+ * If set to 0, the session will be considered fresh every time. (⚠︎ not recommended)
683
+ *
684
+ * @default 1 day (60 * 60 * 24)
685
+ */
686
+ freshAge?: number;
687
+ };
688
+ account?: {
689
+ /**
690
+ * The model name for the account. Defaults to "account".
691
+ */
692
+ modelName?: string;
693
+ /**
694
+ * Map fields
695
+ */
696
+ fields?: Partial<Record<keyof OmitId<Account>, string>>;
697
+ /**
698
+ * Additional fields for the account
699
+ */
700
+ additionalFields?: {
701
+ [key: string]: DBFieldAttribute;
702
+ };
703
+ /**
704
+ * When enabled (true), the user account data (accessToken, idToken, refreshToken, etc.)
705
+ * will be updated on sign in with the latest data from the provider.
706
+ *
707
+ * @default true
708
+ */
709
+ updateAccountOnSignIn?: boolean;
710
+ /**
711
+ * Configuration for account linking.
712
+ */
713
+ accountLinking?: {
714
+ /**
715
+ * Enable account linking
716
+ *
717
+ * @default true
718
+ */
719
+ enabled?: boolean;
720
+ /**
721
+ * List of trusted providers
722
+ */
723
+ trustedProviders?: Array<
724
+ LiteralUnion<SocialProviderList[number] | "email-password", string>
725
+ >;
726
+ /**
727
+ * If enabled (true), this will allow users to manually linking accounts with different email addresses than the main user.
728
+ *
729
+ * @default false
730
+ *
731
+ * ⚠️ Warning: enabling this might lead to account takeovers, so proceed with caution.
732
+ */
733
+ allowDifferentEmails?: boolean;
734
+ /**
735
+ * If enabled (true), this will allow users to unlink all accounts.
736
+ *
737
+ * @default false
738
+ */
739
+ allowUnlinkingAll?: boolean;
740
+ /**
741
+ * If enabled (true), this will update the user information based on the newly linked account
742
+ *
743
+ * @default false
744
+ */
745
+ updateUserInfoOnLink?: boolean;
746
+ };
747
+ /**
748
+ * Encrypt OAuth tokens
749
+ *
750
+ * By default, OAuth tokens (access tokens, refresh tokens, ID tokens) are stored in plain text in the database.
751
+ * This poses a security risk if your database is compromised, as attackers could gain access to user accounts
752
+ * on external services.
753
+ *
754
+ * When enabled, tokens are encrypted using AES-256-GCM before storage, providing protection against:
755
+ * - Database breaches and unauthorized access to raw token data
756
+ * - Internal threats from database administrators or compromised credentials
757
+ * - Token exposure in database backups and logs
758
+ * @default false
759
+ */
760
+ encryptOAuthTokens?: boolean;
761
+ };
762
+ /**
763
+ * Verification configuration
764
+ */
765
+ verification?: {
766
+ /**
767
+ * Change the modelName of the verification table
768
+ */
769
+ modelName?: string;
770
+ /**
771
+ * Map verification fields
772
+ */
773
+ fields?: Partial<Record<keyof OmitId<Verification>, string>>;
774
+ /**
775
+ * disable cleaning up expired values when a verification value is
776
+ * fetched
777
+ */
778
+ disableCleanup?: boolean;
779
+ };
780
+ /**
781
+ * List of trusted origins.
782
+ */
783
+ trustedOrigins?:
784
+ | string[]
785
+ | ((request: Request) => string[] | Promise<string[]>);
786
+ /**
787
+ * Rate limiting configuration
788
+ */
789
+ rateLimit?: BetterAuthRateLimitOptions;
790
+ /**
791
+ * Advanced options
792
+ */
793
+ advanced?: BetterAuthAdvancedOptions & {
794
+ /**
795
+ * @deprecated Please use `database.generateId` instead.
796
+ */
797
+ generateId?: never;
798
+ };
799
+ logger?: Logger;
800
+ /**
801
+ * allows you to define custom hooks that can be
802
+ * executed during lifecycle of core database
803
+ * operations.
804
+ */
805
+ databaseHooks?: {
806
+ /**
807
+ * User hooks
808
+ */
809
+ user?: {
810
+ create?: {
811
+ /**
812
+ * Hook that is called before a user is created.
813
+ * if the hook returns false, the user will not be created.
814
+ * If the hook returns an object, it'll be used instead of the original data
815
+ */
816
+ before?: (
817
+ user: User & Record<string, unknown>,
818
+ context?: GenericEndpointContext,
819
+ ) => Promise<
820
+ | boolean
821
+ | void
822
+ | {
823
+ data: Partial<User> & Record<string, any>;
824
+ }
825
+ >;
826
+ /**
827
+ * Hook that is called after a user is created.
828
+ */
829
+ after?: (
830
+ user: User & Record<string, unknown>,
831
+ context?: GenericEndpointContext,
832
+ ) => Promise<void>;
833
+ };
834
+ update?: {
835
+ /**
836
+ * Hook that is called before a user is updated.
837
+ * if the hook returns false, the user will not be updated.
838
+ * If the hook returns an object, it'll be used instead of the original data
839
+ */
840
+ before?: (
841
+ user: Partial<User> & Record<string, unknown>,
842
+ context?: GenericEndpointContext,
843
+ ) => Promise<
844
+ | boolean
845
+ | void
846
+ | {
847
+ data: Partial<User & Record<string, any>>;
848
+ }
849
+ >;
850
+ /**
851
+ * Hook that is called after a user is updated.
852
+ */
853
+ after?: (
854
+ user: User & Record<string, unknown>,
855
+ context?: GenericEndpointContext,
856
+ ) => Promise<void>;
857
+ };
858
+ delete?: {
859
+ /**
860
+ * Hook that is called before a user is deleted.
861
+ * if the hook returns false, the user will not be deleted.
862
+ */
863
+ before?: (
864
+ user: User & Record<string, unknown>,
865
+ context?: GenericEndpointContext,
866
+ ) => Promise<boolean | void>;
867
+ /**
868
+ * Hook that is called after a user is deleted.
869
+ */
870
+ after?: (
871
+ user: User & Record<string, unknown>,
872
+ context?: GenericEndpointContext,
873
+ ) => Promise<void>;
874
+ };
875
+ };
876
+ /**
877
+ * Session Hook
878
+ */
879
+ session?: {
880
+ create?: {
881
+ /**
882
+ * Hook that is called before a session is created.
883
+ * if the hook returns false, the session will not be created.
884
+ * If the hook returns an object, it'll be used instead of the original data
885
+ */
886
+ before?: (
887
+ session: Session & Record<string, unknown>,
888
+ context?: GenericEndpointContext,
889
+ ) => Promise<
890
+ | boolean
891
+ | void
892
+ | {
893
+ data: Partial<Session> & Record<string, any>;
894
+ }
895
+ >;
896
+ /**
897
+ * Hook that is called after a session is created.
898
+ */
899
+ after?: (
900
+ session: Session & Record<string, unknown>,
901
+ context?: GenericEndpointContext,
902
+ ) => Promise<void>;
903
+ };
904
+ /**
905
+ * Update hook
906
+ */
907
+ update?: {
908
+ /**
909
+ * Hook that is called before a user is updated.
910
+ * if the hook returns false, the session will not be updated.
911
+ * If the hook returns an object, it'll be used instead of the original data
912
+ */
913
+ before?: (
914
+ session: Partial<Session> & Record<string, unknown>,
915
+ context?: GenericEndpointContext,
916
+ ) => Promise<
917
+ | boolean
918
+ | void
919
+ | {
920
+ data: Partial<Session & Record<string, any>>;
921
+ }
922
+ >;
923
+ /**
924
+ * Hook that is called after a session is updated.
925
+ */
926
+ after?: (
927
+ session: Session & Record<string, unknown>,
928
+ context?: GenericEndpointContext,
929
+ ) => Promise<void>;
930
+ };
931
+ delete?: {
932
+ /**
933
+ * Hook that is called before a session is deleted.
934
+ * if the hook returns false, the session will not be deleted.
935
+ */
936
+ before?: (
937
+ session: Session & Record<string, unknown>,
938
+ context?: GenericEndpointContext,
939
+ ) => Promise<boolean | void>;
940
+ /**
941
+ * Hook that is called after a session is deleted.
942
+ */
943
+ after?: (
944
+ session: Session & Record<string, unknown>,
945
+ context?: GenericEndpointContext,
946
+ ) => Promise<void>;
947
+ };
948
+ };
949
+ /**
950
+ * Account Hook
951
+ */
952
+ account?: {
953
+ create?: {
954
+ /**
955
+ * Hook that is called before a account is created.
956
+ * If the hook returns false, the account will not be created.
957
+ * If the hook returns an object, it'll be used instead of the original data
958
+ */
959
+ before?: (
960
+ account: Account,
961
+ context?: GenericEndpointContext,
962
+ ) => Promise<
963
+ | boolean
964
+ | void
965
+ | {
966
+ data: Partial<Account> & Record<string, any>;
967
+ }
968
+ >;
969
+ /**
970
+ * Hook that is called after a account is created.
971
+ */
972
+ after?: (
973
+ account: Account,
974
+ context?: GenericEndpointContext,
975
+ ) => Promise<void>;
976
+ };
977
+ /**
978
+ * Update hook
979
+ */
980
+ update?: {
981
+ /**
982
+ * Hook that is called before a account is update.
983
+ * If the hook returns false, the user will not be updated.
984
+ * If the hook returns an object, it'll be used instead of the original data
985
+ */
986
+ before?: (
987
+ account: Partial<Account> & Record<string, unknown>,
988
+ context?: GenericEndpointContext,
989
+ ) => Promise<
990
+ | boolean
991
+ | void
992
+ | {
993
+ data: Partial<Account & Record<string, any>>;
994
+ }
995
+ >;
996
+ /**
997
+ * Hook that is called after a account is updated.
998
+ */
999
+ after?: (
1000
+ account: Account & Record<string, unknown>,
1001
+ context?: GenericEndpointContext,
1002
+ ) => Promise<void>;
1003
+ };
1004
+ delete?: {
1005
+ /**
1006
+ * Hook that is called before an account is deleted.
1007
+ * if the hook returns false, the account will not be deleted.
1008
+ */
1009
+ before?: (
1010
+ account: Account & Record<string, unknown>,
1011
+ context?: GenericEndpointContext,
1012
+ ) => Promise<boolean | void>;
1013
+ /**
1014
+ * Hook that is called after an account is deleted.
1015
+ */
1016
+ after?: (
1017
+ account: Account & Record<string, unknown>,
1018
+ context?: GenericEndpointContext,
1019
+ ) => Promise<void>;
1020
+ };
1021
+ };
1022
+ /**
1023
+ * Verification Hook
1024
+ */
1025
+ verification?: {
1026
+ create?: {
1027
+ /**
1028
+ * Hook that is called before a verification is created.
1029
+ * if the hook returns false, the verification will not be created.
1030
+ * If the hook returns an object, it'll be used instead of the original data
1031
+ */
1032
+ before?: (
1033
+ verification: Verification & Record<string, unknown>,
1034
+ context?: GenericEndpointContext,
1035
+ ) => Promise<
1036
+ | boolean
1037
+ | void
1038
+ | {
1039
+ data: Partial<Verification> & Record<string, any>;
1040
+ }
1041
+ >;
1042
+ /**
1043
+ * Hook that is called after a verification is created.
1044
+ */
1045
+ after?: (
1046
+ verification: Verification & Record<string, unknown>,
1047
+ context?: GenericEndpointContext,
1048
+ ) => Promise<void>;
1049
+ };
1050
+ update?: {
1051
+ /**
1052
+ * Hook that is called before a verification is updated.
1053
+ * if the hook returns false, the verification will not be updated.
1054
+ * If the hook returns an object, it'll be used instead of the original data
1055
+ */
1056
+ before?: (
1057
+ verification: Partial<Verification> & Record<string, unknown>,
1058
+ context?: GenericEndpointContext,
1059
+ ) => Promise<
1060
+ | boolean
1061
+ | void
1062
+ | {
1063
+ data: Partial<Verification & Record<string, any>>;
1064
+ }
1065
+ >;
1066
+ /**
1067
+ * Hook that is called after a verification is updated.
1068
+ */
1069
+ after?: (
1070
+ verification: Verification & Record<string, unknown>,
1071
+ context?: GenericEndpointContext,
1072
+ ) => Promise<void>;
1073
+ };
1074
+ delete?: {
1075
+ /**
1076
+ * Hook that is called before a verification is deleted.
1077
+ * if the hook returns false, the verification will not be deleted.
1078
+ */
1079
+ before?: (
1080
+ verification: Verification & Record<string, unknown>,
1081
+ context?: GenericEndpointContext,
1082
+ ) => Promise<boolean | void>;
1083
+ /**
1084
+ * Hook that is called after a verification is deleted.
1085
+ */
1086
+ after?: (
1087
+ verification: Verification & Record<string, unknown>,
1088
+ context?: GenericEndpointContext,
1089
+ ) => Promise<void>;
1090
+ };
1091
+ };
1092
+ };
1093
+ /**
1094
+ * API error handling
1095
+ */
1096
+ onAPIError?: {
1097
+ /**
1098
+ * Throw an error on API error
1099
+ *
1100
+ * @default false
1101
+ */
1102
+ throw?: boolean;
1103
+ /**
1104
+ * Custom error handler
1105
+ *
1106
+ * @param error
1107
+ * @param ctx - Auth context
1108
+ */
1109
+ onError?: (error: unknown, ctx: AuthContext) => void | Promise<void>;
1110
+ /**
1111
+ * The URL to redirect to on error
1112
+ *
1113
+ * When errorURL is provided, the error will be added to the URL as a query parameter
1114
+ * and the user will be redirected to the errorURL.
1115
+ *
1116
+ * @default - "/api/auth/error"
1117
+ */
1118
+ errorURL?: string;
1119
+ };
1120
+ /**
1121
+ * Hooks
1122
+ */
1123
+ hooks?: {
1124
+ /**
1125
+ * Before a request is processed
1126
+ */
1127
+ before?: AuthMiddleware;
1128
+ /**
1129
+ * After a request is processed
1130
+ */
1131
+ after?: AuthMiddleware;
1132
+ };
1133
+ /**
1134
+ * Disabled paths
1135
+ *
1136
+ * Paths you want to disable.
1137
+ */
1138
+ disabledPaths?: string[];
1139
+ /**
1140
+ * Telemetry configuration
1141
+ */
1142
+ telemetry?: {
1143
+ /**
1144
+ * Enable telemetry collection
1145
+ *
1146
+ * @default false
1147
+ */
1148
+ enabled?: boolean;
1149
+ /**
1150
+ * Enable debug mode
1151
+ *
1152
+ * @default false
1153
+ */
1154
+ debug?: boolean;
1155
+ };
1156
+ };