@better-auth/core 1.3.26 → 1.3.28

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