@better-auth/core 1.3.27 → 1.3.29

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