better-auth 0.4.7 → 0.4.8

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.
@@ -1,4 +1,4 @@
1
- import { A as Adapter } from '../index-BLNnHUb3.js';
1
+ import { A as Adapter } from '../index-CPq0wKn7.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
4
  import '../types-IzAbV4nB.js';
@@ -13,7 +13,7 @@ var getAuthTables = (options) => {
13
13
  ...acc[key]?.fields,
14
14
  ...value.fields
15
15
  },
16
- tableName: key
16
+ tableName: value.tableName || key
17
17
  };
18
18
  }
19
19
  return acc;
@@ -1,5 +1,5 @@
1
1
  import { Db } from 'mongodb';
2
- import { W as Where } from '../index-BLNnHUb3.js';
2
+ import { W as Where } from '../index-CPq0wKn7.js';
3
3
  import 'zod';
4
4
  import 'kysely';
5
5
  import '../types-IzAbV4nB.js';
@@ -1,4 +1,4 @@
1
- import { A as Adapter } from '../index-BLNnHUb3.js';
1
+ import { A as Adapter } from '../index-CPq0wKn7.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
4
  import '../types-IzAbV4nB.js';
package/dist/api.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { e as AuthEndpoint, f as AuthMiddleware, v as callbackOAuth, T as changePassword, d as createAuthEndpoint, c as createAuthMiddleware, M as createEmailVerificationToken, $ as csrfMiddleware, V as deleteUser, Y as error, J as forgetPassword, K as forgetPasswordCallback, X as getCSRFToken, r as getEndpoints, w as getSession, x as getSessionFromCtx, z as listSessions, Z as ok, o as optionsMiddleware, L as resetPassword, C as revokeSession, D as revokeSessions, s as router, N as sendVerificationEmail, y as sessionMiddleware, U as setPassword, u as signInEmail, t as signInOAuth, E as signOut, _ as signUpEmail, Q as updateUser, O as verifyEmail } from './index-BLNnHUb3.js';
1
+ export { e as AuthEndpoint, f as AuthMiddleware, v as callbackOAuth, T as changePassword, d as createAuthEndpoint, c as createAuthMiddleware, M as createEmailVerificationToken, $ as csrfMiddleware, V as deleteUser, Y as error, J as forgetPassword, K as forgetPasswordCallback, X as getCSRFToken, r as getEndpoints, w as getSession, x as getSessionFromCtx, z as listSessions, Z as ok, o as optionsMiddleware, L as resetPassword, C as revokeSession, D as revokeSessions, s as router, N as sendVerificationEmail, y as sessionMiddleware, U as setPassword, u as signInEmail, t as signInOAuth, E as signOut, _ as signUpEmail, Q as updateUser, O as verifyEmail } from './index-CPq0wKn7.js';
2
2
  import './helper-DPDj8Nix.js';
3
3
  import 'zod';
4
4
  export { APIError } from 'better-call';
package/dist/cli.js CHANGED
@@ -384,7 +384,7 @@ var getAuthTables = (options) => {
384
384
  ...acc[key]?.fields,
385
385
  ...value.fields
386
386
  },
387
- tableName: key
387
+ tableName: value.tableName || key
388
388
  };
389
389
  }
390
390
  return acc;
@@ -1143,7 +1143,7 @@ async function generatePrismaSchema({
1143
1143
  }
1144
1144
  if (attr.references) {
1145
1145
  builder.model(tableName).field(
1146
- `${attr.references.model.toLowerCase()}s`,
1146
+ `${attr.references.model.toLowerCase()}`,
1147
1147
  capitalizeFirstLetter(attr.references.model)
1148
1148
  ).attribute(
1149
1149
  `relation(fields: [${field}], references: [${attr.references.field}], onDelete: Cascade)`
@@ -2,10 +2,10 @@ import * as nanostores from 'nanostores';
2
2
  import { A as AccessControl, S as StatementsPrimitive, R as Role } from '../statement-CfnyN34h.js';
3
3
  import * as _better_fetch_fetch from '@better-fetch/fetch';
4
4
  import { BetterFetchOption } from '@better-fetch/fetch';
5
- import { o as organization, j as Organization, M as Member, I as Invitation, u as username, m as magicLink, d as phoneNumber, e as anonymous, i as admin } from '../index-xf_fyhlx.js';
6
- export { g as getPasskeyActions, c as passkeyClient, a as twoFactorClient } from '../index-xf_fyhlx.js';
5
+ import { o as organization, j as Organization, M as Member, I as Invitation, u as username, m as magicLink, d as phoneNumber, e as anonymous, i as admin } from '../index-BL_Wucme.js';
6
+ export { g as getPasskeyActions, c as passkeyClient, a as twoFactorClient } from '../index-BL_Wucme.js';
7
7
  import { P as Prettify } from '../helper-DPDj8Nix.js';
8
- import { F as FieldAttribute, B as BetterAuthOptions, b as BetterAuthPlugin } from '../index-BLNnHUb3.js';
8
+ import { F as FieldAttribute, B as BetterAuthOptions, b as BetterAuthPlugin } from '../index-CPq0wKn7.js';
9
9
  import * as better_call from 'better-call';
10
10
  import { z } from 'zod';
11
11
  import { O as OAuth2Tokens, U as User } from '../types-IzAbV4nB.js';
@@ -450,7 +450,8 @@ var twoFactorClient = (options = {
450
450
  pathMethods: {
451
451
  "/two-factor/disable": "POST",
452
452
  "/two-factor/enable": "POST",
453
- "/two-factor/send-otp": "POST"
453
+ "/two-factor/send-otp": "POST",
454
+ "/two-factor/generate-backup-codes": "POST"
454
455
  },
455
456
  fetchPlugins: [
456
457
  {
package/dist/client.d.ts CHANGED
@@ -6,7 +6,7 @@ import { BetterFetch, BetterFetchError, BetterFetchOption } from '@better-fetch/
6
6
  import { U as UnionToIntersection, P as Prettify, S as StripEmptyObjects } from './helper-DPDj8Nix.js';
7
7
  import { ClientOptions, InferClientAPI, InferActions, InferAdditionalFromClient, InferSessionFromClient, InferUserFromClient, BetterAuthClientPlugin, IsSignal } from './types.js';
8
8
  export { AtomListener, InferPluginsFromClient } from './types.js';
9
- import './index-BLNnHUb3.js';
9
+ import './index-CPq0wKn7.js';
10
10
  import 'kysely';
11
11
  import './types-IzAbV4nB.js';
12
12
  import 'better-call';
@@ -5,7 +5,7 @@ import { P as Prettify } from './helper-DPDj8Nix.js';
5
5
  import { A as AccessControl, R as Role, S as StatementsPrimitive, g as defaultRoles } from './statement-CfnyN34h.js';
6
6
  import * as _better_fetch_fetch from '@better-fetch/fetch';
7
7
  import { BetterFetch, BetterFetchOption } from '@better-fetch/fetch';
8
- import { H as HookEndpointContext, g as AuthContext } from './index-BLNnHUb3.js';
8
+ import { H as HookEndpointContext, g as AuthContext } from './index-CPq0wKn7.js';
9
9
  import * as nanostores from 'nanostores';
10
10
  import { atom } from 'nanostores';
11
11
  import * as _simplewebauthn_types from '@simplewebauthn/types';
@@ -2563,21 +2563,17 @@ interface TwoFactorOptions {
2563
2563
  * Backup code options
2564
2564
  */
2565
2565
  backupCodeOptions?: BackupCodeOptions;
2566
+ /**
2567
+ * Table name for two factor authentication.
2568
+ * @default "userTwoFactor"
2569
+ */
2570
+ twoFactorTable?: string;
2566
2571
  }
2567
2572
  interface UserWithTwoFactor extends User {
2568
2573
  /**
2569
2574
  * If the user has enabled two factor authentication.
2570
2575
  */
2571
2576
  twoFactorEnabled: boolean;
2572
- /**
2573
- * The secret used to generate the TOTP or OTP.
2574
- */
2575
- twoFactorSecret: string;
2576
- /**
2577
- * List of backup codes separated by a
2578
- * comma
2579
- */
2580
- twoFactorBackupCodes: string;
2581
2577
  }
2582
2578
 
2583
2579
  declare const twoFactorClient: (options?: {
@@ -2599,6 +2595,7 @@ declare const twoFactorClient: (options?: {
2599
2595
  "/two-factor/disable": "POST";
2600
2596
  "/two-factor/enable": "POST";
2601
2597
  "/two-factor/send-otp": "POST";
2598
+ "/two-factor/generate-backup-codes": "POST";
2602
2599
  };
2603
2600
  fetchPlugins: {
2604
2601
  id: string;
@@ -2755,10 +2752,13 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
2755
2752
  method: "POST";
2756
2753
  body: z.ZodObject<{
2757
2754
  code: z.ZodString;
2755
+ disableSession: z.ZodOptional<z.ZodBoolean>;
2758
2756
  }, "strip", z.ZodTypeAny, {
2759
2757
  code: string;
2758
+ disableSession?: boolean | undefined;
2760
2759
  }, {
2761
2760
  code: string;
2761
+ disableSession?: boolean | undefined;
2762
2762
  }>;
2763
2763
  use: better_call.Endpoint<better_call.Handler<string, {
2764
2764
  body: z.ZodObject<{
@@ -2782,7 +2782,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
2782
2782
  headers: Record<string, string> | undefined;
2783
2783
  };
2784
2784
  body: {
2785
- status: boolean;
2785
+ session: {
2786
+ id: string;
2787
+ userId: string;
2788
+ expiresAt: Date;
2789
+ ipAddress?: string | undefined;
2790
+ userAgent?: string | undefined;
2791
+ };
2792
+ user: UserWithTwoFactor;
2786
2793
  };
2787
2794
  _flag: "json";
2788
2795
  }>;
@@ -2810,17 +2817,26 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
2810
2817
  }>]>(...ctx: C): Promise<C extends [{
2811
2818
  asResponse: true;
2812
2819
  }] ? Response : {
2813
- status: boolean;
2820
+ user: UserWithTwoFactor;
2821
+ session: {
2822
+ id: string;
2823
+ userId: string;
2824
+ expiresAt: Date;
2825
+ user: UserWithTwoFactor;
2826
+ };
2814
2827
  }>;
2815
2828
  path: "/two-factor/verify-backup-code";
2816
2829
  options: {
2817
2830
  method: "POST";
2818
2831
  body: z.ZodObject<{
2819
2832
  code: z.ZodString;
2833
+ disableSession: z.ZodOptional<z.ZodBoolean>;
2820
2834
  }, "strip", z.ZodTypeAny, {
2821
2835
  code: string;
2836
+ disableSession?: boolean | undefined;
2822
2837
  }, {
2823
2838
  code: string;
2839
+ disableSession?: boolean | undefined;
2824
2840
  }>;
2825
2841
  use: better_call.Endpoint<better_call.Handler<string, {
2826
2842
  body: z.ZodObject<{
@@ -2844,7 +2860,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
2844
2860
  headers: Record<string, string> | undefined;
2845
2861
  };
2846
2862
  body: {
2847
- status: boolean;
2863
+ session: {
2864
+ id: string;
2865
+ userId: string;
2866
+ expiresAt: Date;
2867
+ ipAddress?: string | undefined;
2868
+ userAgent?: string | undefined;
2869
+ };
2870
+ user: UserWithTwoFactor;
2848
2871
  };
2849
2872
  _flag: "json";
2850
2873
  }>;
@@ -3010,7 +3033,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3010
3033
  headers: Record<string, string> | undefined;
3011
3034
  };
3012
3035
  body: {
3013
- status: boolean;
3036
+ session: {
3037
+ id: string;
3038
+ userId: string;
3039
+ expiresAt: Date;
3040
+ ipAddress?: string | undefined;
3041
+ userAgent?: string | undefined;
3042
+ };
3043
+ user: UserWithTwoFactor;
3014
3044
  };
3015
3045
  _flag: "json";
3016
3046
  }>;
@@ -3065,7 +3095,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3065
3095
  headers: Record<string, string> | undefined;
3066
3096
  };
3067
3097
  body: {
3068
- status: boolean;
3098
+ session: {
3099
+ id: string;
3100
+ userId: string;
3101
+ expiresAt: Date;
3102
+ ipAddress?: string | undefined;
3103
+ userAgent?: string | undefined;
3104
+ };
3105
+ user: UserWithTwoFactor;
3069
3106
  };
3070
3107
  _flag: "json";
3071
3108
  }>;
@@ -3126,7 +3163,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3126
3163
  headers: Record<string, string> | undefined;
3127
3164
  };
3128
3165
  body: {
3129
- status: boolean;
3166
+ session: {
3167
+ id: string;
3168
+ userId: string;
3169
+ expiresAt: Date;
3170
+ ipAddress?: string | undefined;
3171
+ userAgent?: string | undefined;
3172
+ };
3173
+ user: UserWithTwoFactor;
3130
3174
  };
3131
3175
  _flag: "json";
3132
3176
  }>;
@@ -3154,7 +3198,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3154
3198
  }>]>(...ctx: C): Promise<C extends [{
3155
3199
  asResponse: true;
3156
3200
  }] ? Response : {
3157
- status: boolean;
3201
+ session: {
3202
+ id: string;
3203
+ userId: string;
3204
+ expiresAt: Date;
3205
+ ipAddress?: string | undefined;
3206
+ userAgent?: string | undefined;
3207
+ };
3208
+ user: UserWithTwoFactor;
3158
3209
  }>;
3159
3210
  path: "/two-factor/verify-otp";
3160
3211
  options: {
@@ -3188,7 +3239,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3188
3239
  headers: Record<string, string> | undefined;
3189
3240
  };
3190
3241
  body: {
3191
- status: boolean;
3242
+ session: {
3243
+ id: string;
3244
+ userId: string;
3245
+ expiresAt: Date;
3246
+ ipAddress?: string | undefined;
3247
+ userAgent?: string | undefined;
3248
+ };
3249
+ user: UserWithTwoFactor;
3192
3250
  };
3193
3251
  _flag: "json";
3194
3252
  }>;
@@ -3362,7 +3420,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3362
3420
  headers: Record<string, string> | undefined;
3363
3421
  };
3364
3422
  body: {
3365
- status: boolean;
3423
+ session: {
3424
+ id: string;
3425
+ userId: string;
3426
+ expiresAt: Date;
3427
+ ipAddress?: string | undefined;
3428
+ userAgent?: string | undefined;
3429
+ };
3430
+ user: UserWithTwoFactor;
3366
3431
  };
3367
3432
  _flag: "json";
3368
3433
  }>;
@@ -3390,7 +3455,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3390
3455
  }>]>(...ctx: C): Promise<C extends [{
3391
3456
  asResponse: true;
3392
3457
  }] ? Response : {
3393
- status: boolean;
3458
+ session: {
3459
+ id: string;
3460
+ userId: string;
3461
+ expiresAt: Date;
3462
+ ipAddress?: string | undefined;
3463
+ userAgent?: string | undefined;
3464
+ };
3465
+ user: UserWithTwoFactor;
3394
3466
  }>;
3395
3467
  path: "/two-factor/verify-totp";
3396
3468
  options: {
@@ -3427,7 +3499,14 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3427
3499
  headers: Record<string, string> | undefined;
3428
3500
  };
3429
3501
  body: {
3430
- status: boolean;
3502
+ session: {
3503
+ id: string;
3504
+ userId: string;
3505
+ expiresAt: Date;
3506
+ ipAddress?: string | undefined;
3507
+ userAgent?: string | undefined;
3508
+ };
3509
+ user: UserWithTwoFactor;
3431
3510
  };
3432
3511
  _flag: "json";
3433
3512
  }>;
@@ -3474,15 +3553,29 @@ declare const twoFactor: (options?: TwoFactorOptions) => {
3474
3553
  required: false;
3475
3554
  defaultValue: boolean;
3476
3555
  };
3477
- twoFactorSecret: {
3556
+ };
3557
+ };
3558
+ twoFactor: {
3559
+ tableName: string;
3560
+ fields: {
3561
+ secret: {
3478
3562
  type: "string";
3479
- required: false;
3563
+ required: true;
3480
3564
  returned: false;
3481
3565
  };
3482
- twoFactorBackupCodes: {
3566
+ backupCodes: {
3483
3567
  type: "string";
3484
- required: false;
3568
+ required: true;
3569
+ returned: false;
3570
+ };
3571
+ userId: {
3572
+ type: "string";
3573
+ required: true;
3485
3574
  returned: false;
3575
+ references: {
3576
+ model: string;
3577
+ field: string;
3578
+ };
3486
3579
  };
3487
3580
  };
3488
3581
  };
@@ -382,11 +382,12 @@ type InferFieldsFromOptions<Options extends BetterAuthOptions, Key extends "sess
382
382
  } ? Format extends "output" ? InferFieldsOutput<Field> : InferFieldsInput<Field> : {};
383
383
 
384
384
  type PluginSchema = {
385
- [table: string]: {
385
+ [table in string]: {
386
386
  fields: {
387
387
  [field in string]: FieldAttribute;
388
388
  };
389
389
  disableMigration?: boolean;
390
+ tableName?: string;
390
391
  };
391
392
  };
392
393
  type BetterAuthPlugin = {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { a as Auth, a0 as betterAuth } from './index-BLNnHUb3.js';
1
+ export { a as Auth, a0 as betterAuth } from './index-CPq0wKn7.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
4
  import './types-IzAbV4nB.js';
package/dist/index.js CHANGED
@@ -2858,7 +2858,7 @@ var getAuthTables = (options) => {
2858
2858
  ...acc[key]?.fields,
2859
2859
  ...value.fields
2860
2860
  },
2861
- tableName: key
2861
+ tableName: value.tableName || key
2862
2862
  };
2863
2863
  }
2864
2864
  return acc;
package/dist/next-js.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as Auth } from './index-BLNnHUb3.js';
1
+ import { a as Auth } from './index-CPq0wKn7.js';
2
2
  import { U as User, S as Session } from './types-IzAbV4nB.js';
3
3
  import { NextRequest } from 'next/server';
4
4
  import 'zod';
package/dist/node.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as http from 'http';
2
- import { a as Auth } from './index-BLNnHUb3.js';
2
+ import { a as Auth } from './index-CPq0wKn7.js';
3
3
  import 'zod';
4
4
  import 'kysely';
5
5
  import './types-IzAbV4nB.js';
package/dist/plugins.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { A as AnonymousOptions, O as OrganizationOptions, b as Passkey, P as PasskeyOptions, U as UserWithPhoneNumber, f as UserWithRole, i as admin, h as adminMiddleware, e as anonymous, g as getPasskeyActions, m as magicLink, o as organization, p as passkey, c as passkeyClient, d as phoneNumber, t as twoFactor, a as twoFactorClient, u as username } from './index-xf_fyhlx.js';
1
+ export { A as AnonymousOptions, O as OrganizationOptions, b as Passkey, P as PasskeyOptions, U as UserWithPhoneNumber, f as UserWithRole, i as admin, h as adminMiddleware, e as anonymous, g as getPasskeyActions, m as magicLink, o as organization, p as passkey, c as passkeyClient, d as phoneNumber, t as twoFactor, a as twoFactorClient, u as username } from './index-BL_Wucme.js';
2
2
  export { i as ac } from './index-DfAHOgpj.js';
3
- import { H as HookEndpointContext } from './index-BLNnHUb3.js';
4
- export { e as AuthEndpoint, f as AuthMiddleware, b as BetterAuthPlugin, P as PluginSchema, d as createAuthEndpoint, c as createAuthMiddleware, o as optionsMiddleware } from './index-BLNnHUb3.js';
3
+ import { H as HookEndpointContext } from './index-CPq0wKn7.js';
4
+ export { e as AuthEndpoint, f as AuthMiddleware, b as BetterAuthPlugin, P as PluginSchema, d as createAuthEndpoint, c as createAuthMiddleware, o as optionsMiddleware } from './index-CPq0wKn7.js';
5
5
  import './types-IzAbV4nB.js';
6
6
  import 'zod';
7
7
  import './helper-DPDj8Nix.js';
package/dist/plugins.js CHANGED
@@ -4009,10 +4009,15 @@ var verifyTwoFactorMiddleware = createAuthMiddleware(
4009
4009
  return ctx.json({
4010
4010
  status: true,
4011
4011
  callbackURL: ctx.body.callbackURL,
4012
- redirect: true
4012
+ redirect: true,
4013
+ session,
4014
+ user
4013
4015
  });
4014
4016
  }
4015
- return ctx.json({ status: true });
4017
+ return ctx.json({
4018
+ session,
4019
+ user
4020
+ });
4016
4021
  },
4017
4022
  invalid: async () => {
4018
4023
  throw new APIError17("UNAUTHORIZED", {
@@ -4054,15 +4059,15 @@ async function generateBackupCodes(secret, options) {
4054
4059
  };
4055
4060
  }
4056
4061
  async function verifyBackupCode(data, key) {
4057
- const codes = await getBackupCodes(data.user, key);
4062
+ const codes = await getBackupCodes(data.backupCodes, key);
4058
4063
  if (!codes) {
4059
4064
  return false;
4060
4065
  }
4061
4066
  return codes.includes(data.code);
4062
4067
  }
4063
- async function getBackupCodes(user, key) {
4068
+ async function getBackupCodes(backupCodes, key) {
4064
4069
  const secret = Buffer.from(
4065
- await symmetricDecrypt({ key, data: user.twoFactorBackupCodes })
4070
+ await symmetricDecrypt({ key, data: backupCodes })
4066
4071
  ).toString("utf-8");
4067
4072
  const data = JSON.parse(secret);
4068
4073
  const result = z18.array(z18.string()).safeParse(data);
@@ -4071,7 +4076,7 @@ async function getBackupCodes(user, key) {
4071
4076
  }
4072
4077
  return null;
4073
4078
  }
4074
- var backupCode2fa = (options) => {
4079
+ var backupCode2fa = (options, twoFactorTable) => {
4075
4080
  return {
4076
4081
  id: "backup_code",
4077
4082
  endpoints: {
@@ -4080,14 +4085,33 @@ var backupCode2fa = (options) => {
4080
4085
  {
4081
4086
  method: "POST",
4082
4087
  body: z18.object({
4083
- code: z18.string()
4088
+ code: z18.string(),
4089
+ /**
4090
+ * Disable setting the session cookie
4091
+ */
4092
+ disableSession: z18.boolean().optional()
4084
4093
  }),
4085
4094
  use: [verifyTwoFactorMiddleware]
4086
4095
  },
4087
4096
  async (ctx) => {
4097
+ const user = ctx.context.session.user;
4098
+ const twoFactor2 = await ctx.context.adapter.findOne({
4099
+ model: twoFactorTable,
4100
+ where: [
4101
+ {
4102
+ field: "userId",
4103
+ value: user.id
4104
+ }
4105
+ ]
4106
+ });
4107
+ if (!twoFactor2) {
4108
+ throw new APIError18("BAD_REQUEST", {
4109
+ message: "Backup codes aren't enabled"
4110
+ });
4111
+ }
4088
4112
  const validate = verifyBackupCode(
4089
4113
  {
4090
- user: ctx.context.session.user,
4114
+ backupCodes: twoFactor2.backupCodes,
4091
4115
  code: ctx.body.code
4092
4116
  },
4093
4117
  ctx.context.secret
@@ -4097,7 +4121,13 @@ var backupCode2fa = (options) => {
4097
4121
  message: "Invalid backup code"
4098
4122
  });
4099
4123
  }
4100
- return ctx.json({ status: true });
4124
+ if (!ctx.body.disableSession) {
4125
+ await setSessionCookie(ctx, ctx.context.session.id);
4126
+ }
4127
+ return ctx.json({
4128
+ user,
4129
+ session: ctx.context.session
4130
+ });
4101
4131
  }
4102
4132
  ),
4103
4133
  generateBackupCodes: createAuthEndpoint(
@@ -4107,19 +4137,24 @@ var backupCode2fa = (options) => {
4107
4137
  use: [sessionMiddleware]
4108
4138
  },
4109
4139
  async (ctx) => {
4140
+ const user = ctx.context.session.user;
4141
+ if (!user.twoFactorEnabled) {
4142
+ throw new APIError18("BAD_REQUEST", {
4143
+ message: "Two factor isn't enabled"
4144
+ });
4145
+ }
4110
4146
  const backupCodes = await generateBackupCodes(
4111
4147
  ctx.context.secret,
4112
4148
  options
4113
4149
  );
4114
4150
  await ctx.context.adapter.update({
4115
- model: "user",
4151
+ model: twoFactorTable,
4116
4152
  update: {
4117
- twoFactorEnabled: true,
4118
- twoFactorBackupCodes: backupCodes.encryptedBackupCodes
4153
+ backupCodes: backupCodes.encryptedBackupCodes
4119
4154
  },
4120
4155
  where: [
4121
4156
  {
4122
- field: "id",
4157
+ field: "userId",
4123
4158
  value: ctx.context.session.user.id
4124
4159
  }
4125
4160
  ]
@@ -4138,7 +4173,29 @@ var backupCode2fa = (options) => {
4138
4173
  },
4139
4174
  async (ctx) => {
4140
4175
  const user = ctx.context.session.user;
4141
- const backupCodes = getBackupCodes(user, ctx.context.secret);
4176
+ const twoFactor2 = await ctx.context.adapter.findOne({
4177
+ model: twoFactorTable,
4178
+ where: [
4179
+ {
4180
+ field: "userId",
4181
+ value: user.id
4182
+ }
4183
+ ]
4184
+ });
4185
+ if (!twoFactor2) {
4186
+ throw new APIError18("BAD_REQUEST", {
4187
+ message: "Backup codes aren't enabled"
4188
+ });
4189
+ }
4190
+ const backupCodes = getBackupCodes(
4191
+ twoFactor2.backupCodes,
4192
+ ctx.context.secret
4193
+ );
4194
+ if (!backupCodes) {
4195
+ throw new APIError18("BAD_REQUEST", {
4196
+ message: "Backup codes aren't enabled"
4197
+ });
4198
+ }
4142
4199
  return ctx.json({
4143
4200
  status: true,
4144
4201
  backupCodes
@@ -4154,8 +4211,9 @@ import { APIError as APIError19 } from "better-call";
4154
4211
  import { TOTPController } from "oslo/otp";
4155
4212
  import { z as z19 } from "zod";
4156
4213
  import { TimeSpan as TimeSpan4 } from "oslo";
4157
- var otp2fa = (options) => {
4214
+ var otp2fa = (options, twoFactorTable) => {
4158
4215
  const opts = {
4216
+ ...options,
4159
4217
  period: new TimeSpan4(options?.period || 3, "m")
4160
4218
  };
4161
4219
  const totp = new TOTPController({
@@ -4178,7 +4236,21 @@ var otp2fa = (options) => {
4178
4236
  });
4179
4237
  }
4180
4238
  const user = ctx.context.session.user;
4181
- const code = await totp.generate(Buffer.from(user.twoFactorSecret));
4239
+ const twoFactor2 = await ctx.context.adapter.findOne({
4240
+ model: twoFactorTable,
4241
+ where: [
4242
+ {
4243
+ field: "userId",
4244
+ value: user.id
4245
+ }
4246
+ ]
4247
+ });
4248
+ if (!twoFactor2) {
4249
+ throw new APIError19("BAD_REQUEST", {
4250
+ message: "totp isn't enabled"
4251
+ });
4252
+ }
4253
+ const code = await totp.generate(Buffer.from(twoFactor2.secret));
4182
4254
  await options.sendOTP(user, code);
4183
4255
  return ctx.json({ status: true });
4184
4256
  }
@@ -4199,7 +4271,21 @@ var otp2fa = (options) => {
4199
4271
  message: "two factor isn't enabled"
4200
4272
  });
4201
4273
  }
4202
- const toCheckOtp = await totp.generate(Buffer.from(user.twoFactorSecret));
4274
+ const twoFactor2 = await ctx.context.adapter.findOne({
4275
+ model: twoFactorTable,
4276
+ where: [
4277
+ {
4278
+ field: "userId",
4279
+ value: user.id
4280
+ }
4281
+ ]
4282
+ });
4283
+ if (!twoFactor2) {
4284
+ throw new APIError19("BAD_REQUEST", {
4285
+ message: "totp isn't enabled"
4286
+ });
4287
+ }
4288
+ const toCheckOtp = await totp.generate(Buffer.from(twoFactor2.secret));
4203
4289
  if (toCheckOtp === ctx.body.code) {
4204
4290
  return ctx.context.valid();
4205
4291
  } else {
@@ -4221,8 +4307,9 @@ import { APIError as APIError20 } from "better-call";
4221
4307
  import { TimeSpan as TimeSpan5 } from "oslo";
4222
4308
  import { TOTPController as TOTPController2, createTOTPKeyURI } from "oslo/otp";
4223
4309
  import { z as z20 } from "zod";
4224
- var totp2fa = (options) => {
4310
+ var totp2fa = (options, twoFactorTable) => {
4225
4311
  const opts = {
4312
+ ...options,
4226
4313
  digits: 6,
4227
4314
  period: new TimeSpan5(options?.period || 30, "s")
4228
4315
  };
@@ -4241,9 +4328,23 @@ var totp2fa = (options) => {
4241
4328
  message: "totp isn't configured"
4242
4329
  });
4243
4330
  }
4244
- const session = ctx.context.session.user;
4331
+ const user = ctx.context.session.user;
4332
+ const twoFactor2 = await ctx.context.adapter.findOne({
4333
+ model: twoFactorTable,
4334
+ where: [
4335
+ {
4336
+ field: "userId",
4337
+ value: user.id
4338
+ }
4339
+ ]
4340
+ });
4341
+ if (!twoFactor2) {
4342
+ throw new APIError20("BAD_REQUEST", {
4343
+ message: "totp isn't enabled"
4344
+ });
4345
+ }
4245
4346
  const totp = new TOTPController2(opts);
4246
- const code = await totp.generate(Buffer.from(session.twoFactorSecret));
4347
+ const code = await totp.generate(Buffer.from(twoFactor2.secret));
4247
4348
  return { code };
4248
4349
  }
4249
4350
  );
@@ -4263,7 +4364,16 @@ var totp2fa = (options) => {
4263
4364
  });
4264
4365
  }
4265
4366
  const user = ctx.context.session.user;
4266
- if (!user.twoFactorSecret) {
4367
+ const twoFactor2 = await ctx.context.adapter.findOne({
4368
+ model: twoFactorTable,
4369
+ where: [
4370
+ {
4371
+ field: "userId",
4372
+ value: user.id
4373
+ }
4374
+ ]
4375
+ });
4376
+ if (!twoFactor2 || !user.twoFactorEnabled) {
4267
4377
  throw new APIError20("BAD_REQUEST", {
4268
4378
  message: "totp isn't enabled"
4269
4379
  });
@@ -4272,7 +4382,7 @@ var totp2fa = (options) => {
4272
4382
  totpURI: createTOTPKeyURI(
4273
4383
  options?.issuer || "BetterAuth",
4274
4384
  user.email,
4275
- Buffer.from(user.twoFactorSecret),
4385
+ Buffer.from(twoFactor2.secret),
4276
4386
  opts
4277
4387
  )
4278
4388
  };
@@ -4297,10 +4407,25 @@ var totp2fa = (options) => {
4297
4407
  message: "totp isn't configured"
4298
4408
  });
4299
4409
  }
4410
+ const user = ctx.context.session.user;
4411
+ const twoFactor2 = await ctx.context.adapter.findOne({
4412
+ model: twoFactorTable,
4413
+ where: [
4414
+ {
4415
+ field: "userId",
4416
+ value: user.id
4417
+ }
4418
+ ]
4419
+ });
4420
+ if (!twoFactor2 || !twoFactor2.enabled) {
4421
+ throw new APIError20("BAD_REQUEST", {
4422
+ message: "totp isn't enabled"
4423
+ });
4424
+ }
4300
4425
  const totp = new TOTPController2(opts);
4301
4426
  const decrypted = await symmetricDecrypt({
4302
4427
  key: ctx.context.secret,
4303
- data: ctx.context.session.user.twoFactorSecret
4428
+ data: twoFactor2.secret
4304
4429
  });
4305
4430
  const secret = Buffer.from(decrypted);
4306
4431
  const status = await totp.verify(ctx.body.code, secret);
@@ -4357,7 +4482,8 @@ var twoFactorClient = (options = {
4357
4482
  pathMethods: {
4358
4483
  "/two-factor/disable": "POST",
4359
4484
  "/two-factor/enable": "POST",
4360
- "/two-factor/send-otp": "POST"
4485
+ "/two-factor/send-otp": "POST",
4486
+ "/two-factor/generate-backup-codes": "POST"
4361
4487
  },
4362
4488
  fetchPlugins: [
4363
4489
  {
@@ -4381,12 +4507,28 @@ var twoFactorClient = (options = {
4381
4507
 
4382
4508
  // src/plugins/two-factor/index.ts
4383
4509
  var twoFactor = (options) => {
4384
- const totp = totp2fa({
4385
- issuer: options?.issuer || "better-auth",
4386
- ...options?.totpOptions
4387
- });
4388
- const backupCode = backupCode2fa(options?.backupCodeOptions);
4389
- const otp = otp2fa(options?.otpOptions);
4510
+ const opts = {
4511
+ twoFactorTable: options?.twoFactorTable || "twoFactor"
4512
+ };
4513
+ const totp = totp2fa(
4514
+ {
4515
+ issuer: options?.issuer || "better-auth",
4516
+ ...options?.totpOptions
4517
+ },
4518
+ opts.twoFactorTable
4519
+ );
4520
+ const backupCode = backupCode2fa(
4521
+ {
4522
+ ...options?.backupCodeOptions
4523
+ },
4524
+ opts.twoFactorTable
4525
+ );
4526
+ const otp = otp2fa(
4527
+ {
4528
+ ...options?.otpOptions
4529
+ },
4530
+ opts.twoFactorTable
4531
+ );
4390
4532
  return {
4391
4533
  id: "two-factor",
4392
4534
  endpoints: {
@@ -4423,19 +4565,16 @@ var twoFactor = (options) => {
4423
4565
  ctx.context.secret,
4424
4566
  options?.backupCodeOptions
4425
4567
  );
4426
- await ctx.context.adapter.update({
4427
- model: "user",
4428
- update: {
4429
- twoFactorSecret: encryptedSecret,
4430
- twoFactorEnabled: true,
4431
- twoFactorBackupCodes: backupCodes.encryptedBackupCodes
4432
- },
4433
- where: [
4434
- {
4435
- field: "id",
4436
- value: user.id
4437
- }
4438
- ]
4568
+ await ctx.context.internalAdapter.updateUser(user.id, {
4569
+ twoFactorEnabled: true
4570
+ });
4571
+ const res = await ctx.context.adapter.create({
4572
+ model: opts.twoFactorTable,
4573
+ data: {
4574
+ secret: encryptedSecret,
4575
+ backupCodes: backupCodes.encryptedBackupCodes,
4576
+ userId: user.id
4577
+ }
4439
4578
  });
4440
4579
  return ctx.json({ status: true });
4441
4580
  }
@@ -4461,14 +4600,14 @@ var twoFactor = (options) => {
4461
4600
  message: "Invalid password"
4462
4601
  });
4463
4602
  }
4464
- await ctx.context.adapter.update({
4465
- model: "user",
4466
- update: {
4467
- twoFactorEnabled: false
4468
- },
4603
+ await ctx.context.internalAdapter.updateUser(user.id, {
4604
+ twoFactorEnabled: false
4605
+ });
4606
+ await ctx.context.adapter.delete({
4607
+ model: opts.twoFactorTable,
4469
4608
  where: [
4470
4609
  {
4471
- field: "id",
4610
+ field: "userId",
4472
4611
  value: user.id
4473
4612
  }
4474
4613
  ]
@@ -4567,16 +4706,30 @@ var twoFactor = (options) => {
4567
4706
  type: "boolean",
4568
4707
  required: false,
4569
4708
  defaultValue: false
4570
- },
4571
- twoFactorSecret: {
4709
+ }
4710
+ }
4711
+ },
4712
+ twoFactor: {
4713
+ tableName: opts.twoFactorTable,
4714
+ fields: {
4715
+ secret: {
4572
4716
  type: "string",
4573
- required: false,
4717
+ required: true,
4574
4718
  returned: false
4575
4719
  },
4576
- twoFactorBackupCodes: {
4720
+ backupCodes: {
4577
4721
  type: "string",
4578
- required: false,
4722
+ required: true,
4579
4723
  returned: false
4724
+ },
4725
+ userId: {
4726
+ type: "string",
4727
+ required: true,
4728
+ returned: false,
4729
+ references: {
4730
+ model: "user",
4731
+ field: "id"
4732
+ }
4580
4733
  }
4581
4734
  }
4582
4735
  }
package/dist/react.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as _better_fetch_fetch from '@better-fetch/fetch';
3
3
  import { U as UnionToIntersection, P as Prettify, S as StripEmptyObjects } from './helper-DPDj8Nix.js';
4
4
  import { ClientOptions, InferClientAPI, InferActions, InferAdditionalFromClient, BetterAuthClientPlugin, IsSignal } from './types.js';
5
5
  import { useStore } from '@nanostores/react';
6
- import './index-BLNnHUb3.js';
6
+ import './index-CPq0wKn7.js';
7
7
  import 'kysely';
8
8
  import './types-IzAbV4nB.js';
9
9
  import 'better-call';
@@ -1,4 +1,4 @@
1
- import { a as Auth } from './index-BLNnHUb3.js';
1
+ import { a as Auth } from './index-CPq0wKn7.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
4
  import './types-IzAbV4nB.js';
package/dist/solid.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as _better_fetch_fetch from '@better-fetch/fetch';
3
3
  import { U as UnionToIntersection, P as Prettify, S as StripEmptyObjects } from './helper-DPDj8Nix.js';
4
4
  import { ClientOptions, InferClientAPI, InferActions, InferAdditionalFromClient, BetterAuthClientPlugin, IsSignal } from './types.js';
5
5
  import { Accessor } from 'solid-js';
6
- import './index-BLNnHUb3.js';
6
+ import './index-CPq0wKn7.js';
7
7
  import 'kysely';
8
8
  import './types-IzAbV4nB.js';
9
9
  import 'better-call';
@@ -1,4 +1,4 @@
1
- import { a as Auth, B as BetterAuthOptions } from './index-BLNnHUb3.js';
1
+ import { a as Auth, B as BetterAuthOptions } from './index-CPq0wKn7.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
4
  import './types-IzAbV4nB.js';
package/dist/svelte.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as nanostores from 'nanostores';
3
3
  import * as _better_fetch_fetch from '@better-fetch/fetch';
4
4
  import { U as UnionToIntersection, P as Prettify, S as StripEmptyObjects } from './helper-DPDj8Nix.js';
5
5
  import { ClientOptions, InferClientAPI, InferActions, InferAdditionalFromClient, BetterAuthClientPlugin, IsSignal } from './types.js';
6
- import './index-BLNnHUb3.js';
6
+ import './index-CPq0wKn7.js';
7
7
  import 'kysely';
8
8
  import './types-IzAbV4nB.js';
9
9
  import 'better-call';
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { b as BetterAuthPlugin, a as Auth, I as InferFieldsInputClient, h as InferFieldsOutput } from './index-BLNnHUb3.js';
2
- export { A as Adapter, k as AdditionalSessionFieldsInput, l as AdditionalSessionFieldsOutput, i as AdditionalUserFieldsInput, j as AdditionalUserFieldsOutput, g as AuthContext, B as BetterAuthOptions, G as GenericEndpointContext, H as HookEndpointContext, p as InferPluginTypes, n as InferSession, m as InferUser, P as PluginSchema, R as RateLimit, S as SecondaryStorage, W as Where, q as init } from './index-BLNnHUb3.js';
1
+ import { b as BetterAuthPlugin, a as Auth, I as InferFieldsInputClient, h as InferFieldsOutput } from './index-CPq0wKn7.js';
2
+ export { A as Adapter, k as AdditionalSessionFieldsInput, l as AdditionalSessionFieldsOutput, i as AdditionalUserFieldsInput, j as AdditionalUserFieldsOutput, g as AuthContext, B as BetterAuthOptions, G as GenericEndpointContext, H as HookEndpointContext, p as InferPluginTypes, n as InferSession, m as InferUser, P as PluginSchema, R as RateLimit, S as SecondaryStorage, W as Where, q as init } from './index-CPq0wKn7.js';
3
3
  import { U as UnionToIntersection, H as HasRequiredKeys, P as Prettify, S as StripEmptyObjects, L as LiteralString } from './helper-DPDj8Nix.js';
4
4
  export { D as DeepPartial, a as LiteralUnion, R as RequiredKeysOf, W as WithoutEmpty } from './helper-DPDj8Nix.js';
5
5
  import { S as Session, U as User } from './types-IzAbV4nB.js';
package/dist/vue.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as _better_fetch_fetch from '@better-fetch/fetch';
3
3
  import { U as UnionToIntersection, P as Prettify, S as StripEmptyObjects } from './helper-DPDj8Nix.js';
4
4
  import { ClientOptions, InferClientAPI, InferActions, InferAdditionalFromClient, BetterAuthClientPlugin, IsSignal } from './types.js';
5
5
  import { Ref, DeepReadonly } from 'vue';
6
- import './index-BLNnHUb3.js';
6
+ import './index-CPq0wKn7.js';
7
7
  import 'kysely';
8
8
  import './types-IzAbV4nB.js';
9
9
  import 'better-call';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "The most comprehensive authentication library for TypeScript.",
5
5
  "type": "module",
6
6
  "repository": {