better-auth 0.0.8-beta.2 → 0.0.8-beta.21

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 (58) hide show
  1. package/dist/access.d.ts +3 -4
  2. package/dist/access.js +3 -13
  3. package/dist/access.js.map +1 -1
  4. package/dist/cli.d.ts +1 -2
  5. package/dist/cli.js +36 -44
  6. package/dist/cli.js.map +1 -1
  7. package/dist/client/plugins.d.ts +97 -2407
  8. package/dist/client/plugins.js +143 -203
  9. package/dist/client/plugins.js.map +1 -1
  10. package/dist/client.d.ts +159 -1213
  11. package/dist/client.js +125 -527
  12. package/dist/client.js.map +1 -1
  13. package/dist/{helper-B5_2Vzba.d.ts → helper-D8dhRz72.d.ts} +1 -4
  14. package/dist/{index-Dg4eEXZW.d.ts → index-B9jOjqnF.d.ts} +1 -1
  15. package/dist/{schema-BOszzrbQ.d.ts → index-CcxejJTH.d.ts} +172 -142
  16. package/dist/{client-CaF9eUcv.d.ts → index-Dwhjsk4l.d.ts} +2014 -1971
  17. package/dist/index.d.ts +1124 -6
  18. package/dist/index.js +737 -707
  19. package/dist/index.js.map +1 -1
  20. package/dist/internal-adapter-CVKQ4XR9.d.ts +637 -0
  21. package/dist/next-js.d.ts +17 -7
  22. package/dist/next-js.js +20 -3
  23. package/dist/next-js.js.map +1 -1
  24. package/dist/plugins.d.ts +12 -883
  25. package/dist/plugins.js +743 -679
  26. package/dist/plugins.js.map +1 -1
  27. package/dist/react.d.ts +312 -12
  28. package/dist/react.js +138 -148
  29. package/dist/react.js.map +1 -1
  30. package/dist/social.d.ts +2 -2
  31. package/dist/social.js +179 -151
  32. package/dist/social.js.map +1 -1
  33. package/dist/solid-start.d.ts +7 -6
  34. package/dist/solid-start.js +3 -3
  35. package/dist/solid-start.js.map +1 -1
  36. package/dist/solid.d.ts +91 -2713
  37. package/dist/solid.js +130 -139
  38. package/dist/solid.js.map +1 -1
  39. package/dist/{statement-COylZd3J.d.ts → statement-D6SPoYOh.d.ts} +7 -7
  40. package/dist/svelte-kit.d.ts +6 -5
  41. package/dist/svelte-kit.js +10 -9
  42. package/dist/svelte-kit.js.map +1 -1
  43. package/dist/svelte.d.ts +89 -2713
  44. package/dist/svelte.js +124 -138
  45. package/dist/svelte.js.map +1 -1
  46. package/dist/types-D4WrjKeJ.d.ts +81 -0
  47. package/dist/types.d.ts +31 -5
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -1
  50. package/dist/vue.d.ts +313 -12
  51. package/dist/vue.js +131 -145
  52. package/dist/vue.js.map +1 -1
  53. package/package.json +8 -3
  54. package/dist/index-CGeV0d2g.d.ts +0 -1498
  55. package/dist/preact.d.ts +0 -8
  56. package/dist/preact.js +0 -291
  57. package/dist/preact.js.map +0 -1
  58. package/dist/type-tYx_kmry.d.ts +0 -5724
package/dist/index.js CHANGED
@@ -1,89 +1,24 @@
1
- // src/api/index.ts
2
- import { createRouter } from "better-call";
3
-
4
- // src/adapters/schema.ts
5
- import { z } from "zod";
6
- var accountSchema = z.object({
7
- id: z.string(),
8
- providerId: z.string(),
9
- accountId: z.string(),
10
- userId: z.string(),
11
- accessToken: z.string().nullable().optional(),
12
- refreshToken: z.string().nullable().optional(),
13
- idToken: z.string().nullable().optional(),
14
- accessTokenExpiresAt: z.date().nullable().optional(),
15
- refreshTokenExpiresAt: z.date().nullable().optional(),
16
- /**
17
- * Password is only stored in the credential provider
18
- */
19
- password: z.string().optional().nullable()
20
- });
21
- var userSchema = z.object({
22
- id: z.string(),
23
- email: z.string().transform((val) => val.toLowerCase()),
24
- emailVerified: z.boolean().default(false),
25
- name: z.string(),
26
- image: z.string().optional(),
27
- createdAt: z.date().default(/* @__PURE__ */ new Date()),
28
- updatedAt: z.date().default(/* @__PURE__ */ new Date())
29
- });
30
- var sessionSchema = z.object({
31
- id: z.string(),
32
- userId: z.string(),
33
- expiresAt: z.date(),
34
- ipAddress: z.string().optional(),
35
- userAgent: z.string().optional()
36
- });
37
- function parseData(data, schema) {
38
- const fields = schema.fields;
39
- const parsedData = {};
40
- for (const key in data) {
41
- const field = fields[key];
42
- if (!field) {
43
- parsedData[key] = data[key];
44
- continue;
45
- }
46
- if (field.returned === false) {
47
- continue;
48
- }
49
- parsedData[key] = data[key];
50
- }
51
- return parsedData;
52
- }
53
- function getAllFields(options, table) {
54
- let schema = {};
55
- for (const plugin of options.plugins || []) {
56
- if (plugin.schema && plugin.schema[table]) {
57
- schema = {
58
- ...schema,
59
- ...plugin.schema[table].fields
60
- };
61
- }
62
- }
63
- return schema;
64
- }
65
- function parseUser(options, user) {
66
- const schema = getAllFields(options, "user");
67
- return parseData(user, { fields: schema });
68
- }
69
- function parseAccount(options, account) {
70
- const schema = getAllFields(options, "account");
71
- return parseData(account, { fields: schema });
72
- }
73
- function parseSession(options, session) {
74
- const schema = getAllFields(options, "session");
75
- return parseData(session, { fields: schema });
76
- }
77
-
78
- // src/api/middlewares/csrf.ts
79
- import { APIError } from "better-call";
80
- import { z as z2 } from "zod";
1
+ import { createMiddleware, createMiddlewareCreator, createEndpointCreator, APIError, createRouter } from 'better-call';
2
+ import { z } from 'zod';
3
+ import '@noble/ciphers/chacha';
4
+ import '@noble/ciphers/utils';
5
+ import '@noble/ciphers/webcrypto';
6
+ import '@noble/hashes/sha256';
7
+ import { generateCodeVerifier, generateState as generateState$1 } from 'oslo/oauth2';
8
+ import { Discord, Facebook, GitHub, Google, Spotify, Twitch, Twitter } from 'arctic';
9
+ import { createJWT, validateJWT, parseJWT } from 'oslo/jwt';
10
+ import { betterFetch } from '@better-fetch/fetch';
11
+ import { createOAuth2Request, sendTokenRequest } from 'arctic/dist/request';
12
+ import { createConsola } from 'consola';
13
+ import { TimeSpan } from 'oslo';
14
+ import { generateRandomString, alphabet } from 'oslo/crypto';
15
+ import Database from 'better-sqlite3';
16
+ import { Kysely, MysqlDialect, PostgresDialect, SqliteDialect } from 'kysely';
17
+ import { createPool } from 'mysql2';
18
+ import pg from 'pg';
19
+ import * as argon2 from 'argon2';
81
20
 
82
- // src/crypto/index.ts
83
- import { xchacha20poly1305 } from "@noble/ciphers/chacha";
84
- import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/ciphers/utils";
85
- import { managedNonce } from "@noble/ciphers/webcrypto";
86
- import { sha256 } from "@noble/hashes/sha256";
21
+ // src/api/index.ts
87
22
  async function hs256(secretKey, message) {
88
23
  const enc = new TextEncoder();
89
24
  const algorithm = { name: "HMAC", hash: "SHA-256" };
@@ -101,18 +36,20 @@ async function hs256(secretKey, message) {
101
36
  );
102
37
  return btoa(String.fromCharCode(...new Uint8Array(signature)));
103
38
  }
104
-
105
- // src/api/call.ts
106
- import {
107
- createEndpointCreator,
108
- createMiddleware,
109
- createMiddlewareCreator
110
- } from "better-call";
111
39
  var optionsMiddleware = createMiddleware(async () => {
112
40
  return {};
113
41
  });
114
42
  var createAuthMiddleware = createMiddlewareCreator({
115
- use: [optionsMiddleware]
43
+ use: [
44
+ optionsMiddleware,
45
+ /**
46
+ * This of for hooks. to tell ts there will a
47
+ * return response object
48
+ */
49
+ createMiddleware(async () => {
50
+ return {};
51
+ })
52
+ ]
116
53
  });
117
54
  var createAuthEndpoint = createEndpointCreator({
118
55
  use: [optionsMiddleware]
@@ -121,8 +58,8 @@ var createAuthEndpoint = createEndpointCreator({
121
58
  // src/api/middlewares/csrf.ts
122
59
  var csrfMiddleware = createAuthMiddleware(
123
60
  {
124
- body: z2.object({
125
- csrfToken: z2.string().optional()
61
+ body: z.object({
62
+ csrfToken: z.string().optional()
126
63
  }).optional()
127
64
  },
128
65
  async (ctx) => {
@@ -130,8 +67,7 @@ var csrfMiddleware = createAuthMiddleware(
130
67
  return;
131
68
  }
132
69
  const url = new URL(ctx.request.url);
133
- console.log(url.origin, ctx.context.options.baseURL);
134
- if (url.origin === ctx.context.options.baseURL || ctx.context.options.trustedOrigins?.includes(url.origin)) {
70
+ if (url.origin === new URL(ctx.context.baseURL).origin || ctx.context.options.trustedOrigins?.includes(url.origin)) {
135
71
  return;
136
72
  }
137
73
  const csrfToken = ctx.body?.csrfToken;
@@ -139,8 +75,8 @@ var csrfMiddleware = createAuthMiddleware(
139
75
  ctx.context.authCookies.csrfToken.name,
140
76
  ctx.context.secret
141
77
  );
142
- const [token, hash] = csrfCookie?.split("!") || [null, null];
143
- if (!csrfToken || !csrfCookie || !token || !hash || csrfCookie !== csrfToken) {
78
+ const [token, hash2] = csrfCookie?.split("!") || [null, null];
79
+ if (!csrfToken || !csrfCookie || !token || !hash2 || csrfCookie !== csrfToken) {
144
80
  ctx.setCookie(ctx.context.authCookies.csrfToken.name, "", {
145
81
  maxAge: 0
146
82
  });
@@ -149,7 +85,7 @@ var csrfMiddleware = createAuthMiddleware(
149
85
  });
150
86
  }
151
87
  const expectedHash = await hs256(ctx.context.secret, token);
152
- if (hash !== expectedHash) {
88
+ if (hash2 !== expectedHash) {
153
89
  ctx.setCookie(ctx.context.authCookies.csrfToken.name, "", {
154
90
  maxAge: 0
155
91
  });
@@ -160,17 +96,6 @@ var csrfMiddleware = createAuthMiddleware(
160
96
  }
161
97
  );
162
98
 
163
- // src/api/routes/sign-in.ts
164
- import { APIError as APIError2 } from "better-call";
165
- import { generateCodeVerifier } from "oslo/oauth2";
166
- import { Argon2id } from "oslo/password";
167
- import { z as z3 } from "zod";
168
-
169
- // src/social-providers/apple.ts
170
- import "arctic";
171
- import { parseJWT } from "oslo/jwt";
172
- import { betterFetch } from "@better-fetch/fetch";
173
-
174
99
  // src/error/better-auth-error.ts
175
100
  var BetterAuthError = class extends Error {
176
101
  constructor(message) {
@@ -191,41 +116,47 @@ function checkHasPath(url) {
191
116
  function withPath(url, path = "/api/auth") {
192
117
  const hasPath = checkHasPath(url);
193
118
  if (hasPath) {
194
- return {
195
- baseURL: new URL(url).origin,
196
- withPath: url
197
- };
119
+ return url;
198
120
  }
199
121
  path = path.startsWith("/") ? path : `/${path}`;
200
- return {
201
- baseURL: url,
202
- withPath: `${url}${path}`
203
- };
122
+ return `${url}${path}`;
204
123
  }
205
124
  function getBaseURL(url, path) {
206
125
  if (url) {
207
126
  return withPath(url, path);
208
127
  }
209
128
  const env = typeof process !== "undefined" ? process.env : {};
210
- const fromEnv = env.BETTER_AUTH_URL || env.AUTH_URL || env.NEXT_PUBLIC_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL;
129
+ const fromEnv = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_BETTER_AUTH_URL || env.PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_BETTER_AUTH_URL || env.NUXT_PUBLIC_AUTH_URL;
211
130
  if (fromEnv) {
212
131
  return withPath(fromEnv, path);
213
132
  }
214
- const isDev = !fromEnv && (env.NODE_ENV === "development" || env.NODE_ENV === "test");
215
- if (isDev) {
216
- return {
217
- baseURL: "http://localhost:3000",
218
- withPath: "http://localhost:3000/api/auth"
219
- };
133
+ if (typeof window !== "undefined") {
134
+ return withPath(window.location.origin, path);
220
135
  }
221
- throw new BetterAuthError(
222
- "Could not infer baseURL from environment variables"
223
- );
136
+ return void 0;
224
137
  }
225
138
 
226
139
  // src/social-providers/utils.ts
227
140
  function getRedirectURI(providerId, redirectURI) {
228
- return redirectURI || `${getBaseURL()}/api/auth/callback/${providerId}`;
141
+ return redirectURI || `${getBaseURL()}/callback/${providerId}`;
142
+ }
143
+ async function validateAuthorizationCode({
144
+ code,
145
+ codeVerifier,
146
+ redirectURI,
147
+ options,
148
+ tokenEndpoint
149
+ }) {
150
+ const body = new URLSearchParams();
151
+ body.set("grant_type", "authorization_code");
152
+ body.set("code", code);
153
+ body.set("code_verifier", codeVerifier || "");
154
+ body.set("redirect_uri", redirectURI);
155
+ body.set("client_id", options.clientId);
156
+ body.set("client_secret", options.clientSecret);
157
+ const request = createOAuth2Request(tokenEndpoint, body);
158
+ const tokens = await sendTokenRequest(request);
159
+ return tokens;
229
160
  }
230
161
 
231
162
  // src/social-providers/apple.ts
@@ -282,19 +213,11 @@ var apple = ({
282
213
  }
283
214
  };
284
215
  };
285
-
286
- // src/social-providers/discord.ts
287
- import { betterFetch as betterFetch2 } from "@better-fetch/fetch";
288
- import { Discord } from "arctic";
289
- var discord = ({
290
- clientId,
291
- clientSecret,
292
- redirectURI
293
- }) => {
216
+ var discord = (options) => {
294
217
  const discordArctic = new Discord(
295
- clientId,
296
- clientSecret,
297
- getRedirectURI("discord", redirectURI)
218
+ options.clientId,
219
+ options.clientSecret,
220
+ getRedirectURI("discord", options.redirectURI)
298
221
  );
299
222
  return {
300
223
  id: "discord",
@@ -303,14 +226,22 @@ var discord = ({
303
226
  const _scope = scopes || ["email"];
304
227
  return discordArctic.createAuthorizationURL(state, _scope);
305
228
  },
306
- validateAuthorizationCode: discordArctic.validateAuthorizationCode,
229
+ validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
230
+ return validateAuthorizationCode({
231
+ code,
232
+ codeVerifier,
233
+ redirectURI: redirectURI || getRedirectURI("discord", options.redirectURI),
234
+ options,
235
+ tokenEndpoint: "https://discord.com/api/oauth2/token"
236
+ });
237
+ },
307
238
  async getUserInfo(token) {
308
- const { data: profile, error: error2 } = await betterFetch2(
239
+ const { data: profile, error: error2 } = await betterFetch(
309
240
  "https://discord.com/api/users/@me",
310
241
  {
311
242
  auth: {
312
243
  type: "Bearer",
313
- token: token.accessToken
244
+ token: token.accessToken()
314
245
  }
315
246
  }
316
247
  );
@@ -329,19 +260,11 @@ var discord = ({
329
260
  }
330
261
  };
331
262
  };
332
-
333
- // src/social-providers/facebook.ts
334
- import { betterFetch as betterFetch3 } from "@better-fetch/fetch";
335
- import { Facebook } from "arctic";
336
- var facebook = ({
337
- clientId,
338
- clientSecret,
339
- redirectURI
340
- }) => {
263
+ var facebook = (options) => {
341
264
  const facebookArctic = new Facebook(
342
- clientId,
343
- clientSecret,
344
- getRedirectURI("facebook", redirectURI)
265
+ options.clientId,
266
+ options.clientSecret,
267
+ getRedirectURI("facebook", options.redirectURI)
345
268
  );
346
269
  return {
347
270
  id: "facebook",
@@ -350,14 +273,22 @@ var facebook = ({
350
273
  const _scopes = scopes || ["email", "public_profile"];
351
274
  return facebookArctic.createAuthorizationURL(state, _scopes);
352
275
  },
353
- validateAuthorizationCode: facebookArctic.validateAuthorizationCode,
276
+ validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
277
+ return validateAuthorizationCode({
278
+ code,
279
+ codeVerifier,
280
+ redirectURI: redirectURI || getRedirectURI("facebook", options.redirectURI),
281
+ options,
282
+ tokenEndpoint: "https://graph.facebook.com/v16.0/oauth/access_token"
283
+ });
284
+ },
354
285
  async getUserInfo(token) {
355
- const { data: profile, error: error2 } = await betterFetch3(
286
+ const { data: profile, error: error2 } = await betterFetch(
356
287
  "https://graph.facebook.com/me",
357
288
  {
358
289
  auth: {
359
290
  type: "Bearer",
360
- token: token.accessToken
291
+ token: token.accessToken()
361
292
  }
362
293
  }
363
294
  );
@@ -376,10 +307,6 @@ var facebook = ({
376
307
  }
377
308
  };
378
309
  };
379
-
380
- // src/social-providers/github.ts
381
- import { betterFetch as betterFetch4 } from "@better-fetch/fetch";
382
- import { GitHub } from "arctic";
383
310
  var github = ({
384
311
  clientId,
385
312
  clientSecret,
@@ -397,14 +324,17 @@ var github = ({
397
324
  const _scopes = scopes || ["user:email"];
398
325
  return githubArctic.createAuthorizationURL(state, _scopes);
399
326
  },
400
- validateAuthorizationCode: githubArctic.validateAuthorizationCode,
327
+ validateAuthorizationCode: async (state) => {
328
+ return await githubArctic.validateAuthorizationCode(state);
329
+ },
401
330
  async getUserInfo(token) {
402
- const { data: profile, error: error2 } = await betterFetch4(
331
+ console.log(`Bearer ${token.accessToken()}`);
332
+ const { data: profile, error: error2 } = await betterFetch(
403
333
  "https://api.github.com/user",
404
334
  {
405
- method: "GET",
406
- headers: {
407
- Authorization: `Bearer ${token.accessToken}`
335
+ auth: {
336
+ type: "Bearer",
337
+ token: token.accessToken()
408
338
  }
409
339
  }
410
340
  );
@@ -413,10 +343,10 @@ var github = ({
413
343
  }
414
344
  let emailVerified = false;
415
345
  if (!profile.email) {
416
- const { data, error: error3 } = await betterFetch4("https://api.github.com/user/emails", {
417
- headers: {
418
- Authorization: `Bearer ${token.accessToken}`,
419
- "User-Agent": "better-auth"
346
+ const { data, error: error3 } = await betterFetch("https://api.github.com/user/emails", {
347
+ auth: {
348
+ type: "Bearer",
349
+ token: token.accessToken()
420
350
  }
421
351
  });
422
352
  if (!error3) {
@@ -439,41 +369,81 @@ var github = ({
439
369
  }
440
370
  };
441
371
  };
442
-
443
- // src/social-providers/google.ts
444
- import { Google } from "arctic";
445
- import { parseJWT as parseJWT2 } from "oslo/jwt";
446
- var google = ({
447
- clientId,
448
- clientSecret,
449
- redirectURI
450
- }) => {
372
+ var consola = createConsola({
373
+ formatOptions: {
374
+ date: false,
375
+ colors: true,
376
+ compact: true
377
+ },
378
+ defaults: {
379
+ tag: "Better Auth"
380
+ }
381
+ });
382
+ var createLogger = (options) => {
383
+ return {
384
+ log: (...args) => {
385
+ !options?.disabled && consola.log("", ...args);
386
+ },
387
+ error: (...args) => {
388
+ !options?.disabled && consola.error("", ...args);
389
+ },
390
+ warn: (...args) => {
391
+ !options?.disabled && consola.warn("", ...args);
392
+ },
393
+ info: (...args) => {
394
+ !options?.disabled && consola.info("", ...args);
395
+ },
396
+ debug: (...args) => {
397
+ !options?.disabled && consola.debug("", ...args);
398
+ },
399
+ box: (...args) => {
400
+ !options?.disabled && consola.box("", ...args);
401
+ },
402
+ success: (...args) => {
403
+ !options?.disabled && consola.success("", ...args);
404
+ },
405
+ break: (...args) => {
406
+ !options?.disabled && console.log("\n");
407
+ }
408
+ };
409
+ };
410
+ var logger = createLogger();
411
+ var google = (options) => {
451
412
  const googleArctic = new Google(
452
- clientId,
453
- clientSecret,
454
- getRedirectURI("google", redirectURI)
413
+ options.clientId,
414
+ options.clientSecret,
415
+ getRedirectURI("google", options.redirectURI)
455
416
  );
456
417
  return {
457
418
  id: "google",
458
419
  name: "Google",
459
- createAuthorizationURL({ state, scopes, codeVerifier }) {
420
+ createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
421
+ if (!options.clientId || !options.clientSecret) {
422
+ logger.error(
423
+ "clientId and clientSecret is required for Google. Make sure to you have provided them in the options"
424
+ );
425
+ throw new BetterAuthError("clientId is required for Google");
426
+ }
460
427
  if (!codeVerifier) {
461
428
  throw new BetterAuthError("codeVerifier is required for Google");
462
429
  }
463
430
  const _scopes = scopes || ["email", "profile"];
464
431
  return googleArctic.createAuthorizationURL(state, codeVerifier, _scopes);
465
432
  },
466
- validateAuthorizationCode: async (code, codeVerifier) => {
467
- if (!codeVerifier) {
468
- throw new BetterAuthError("codeVerifier is required for Google");
469
- }
470
- return googleArctic.validateAuthorizationCode(code, codeVerifier);
433
+ validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
434
+ return validateAuthorizationCode({
435
+ code,
436
+ codeVerifier,
437
+ redirectURI: redirectURI || getRedirectURI("google", options.redirectURI),
438
+ options,
439
+ tokenEndpoint: "https://oauth2.googleapis.com/token"
440
+ });
471
441
  },
472
442
  async getUserInfo(token) {
473
443
  if (!token.idToken) {
474
444
  return null;
475
445
  }
476
- const user = parseJWT2(token.idToken())?.payload;
446
+ const user = parseJWT(token.idToken())?.payload;
477
447
  return {
478
448
  user: {
479
449
  id: user.sub,
@@ -487,19 +457,11 @@ var google = ({
487
457
  }
488
458
  };
489
459
  };
490
-
491
- // src/social-providers/spotify.ts
492
- import { betterFetch as betterFetch5 } from "@better-fetch/fetch";
493
- import { Spotify } from "arctic";
494
- var spotify = ({
495
- clientId,
496
- clientSecret,
497
- redirectURI
498
- }) => {
460
+ var spotify = (options) => {
499
461
  const spotifyArctic = new Spotify(
500
- clientId,
501
- clientSecret,
502
- getRedirectURI("spotify", redirectURI)
462
+ options.clientId,
463
+ options.clientSecret,
464
+ getRedirectURI("spotify", options.redirectURI)
503
465
  );
504
466
  return {
505
467
  id: "spotify",
@@ -508,14 +470,22 @@ var spotify = ({
508
470
  const _scopes = scopes || ["user-read-email"];
509
471
  return spotifyArctic.createAuthorizationURL(state, _scopes);
510
472
  },
511
- validateAuthorizationCode: spotifyArctic.validateAuthorizationCode,
473
+ validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
474
+ return validateAuthorizationCode({
475
+ code,
476
+ codeVerifier,
477
+ redirectURI: redirectURI || getRedirectURI("spotify", options.redirectURI),
478
+ options,
479
+ tokenEndpoint: "https://accounts.spotify.com/api/token"
480
+ });
481
+ },
512
482
  async getUserInfo(token) {
513
- const { data: profile, error: error2 } = await betterFetch5(
483
+ const { data: profile, error: error2 } = await betterFetch(
514
484
  "https://api.spotify.com/v1/me",
515
485
  {
516
486
  method: "GET",
517
487
  headers: {
518
- Authorization: `Bearer ${token.accessToken}`
488
+ Authorization: `Bearer ${token.accessToken()}`
519
489
  }
520
490
  }
521
491
  );
@@ -535,19 +505,11 @@ var spotify = ({
535
505
  }
536
506
  };
537
507
  };
538
-
539
- // src/social-providers/twitch.ts
540
- import { betterFetch as betterFetch6 } from "@better-fetch/fetch";
541
- import { Twitch } from "arctic";
542
- var twitch = ({
543
- clientId,
544
- clientSecret,
545
- redirectURI
546
- }) => {
508
+ var twitch = (options) => {
547
509
  const twitchArctic = new Twitch(
548
- clientId,
549
- clientSecret,
550
- getRedirectURI("twitch", redirectURI)
510
+ options.clientId,
511
+ options.clientSecret,
512
+ getRedirectURI("twitch", options.redirectURI)
551
513
  );
552
514
  return {
553
515
  id: "twitch",
@@ -556,14 +518,22 @@ var twitch = ({
556
518
  const _scopes = scopes || ["activity:write", "read"];
557
519
  return twitchArctic.createAuthorizationURL(state, _scopes);
558
520
  },
559
- validateAuthorizationCode: twitchArctic.validateAuthorizationCode,
521
+ validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
522
+ return validateAuthorizationCode({
523
+ code,
524
+ codeVerifier,
525
+ redirectURI: redirectURI || getRedirectURI("twitch", options.redirectURI),
526
+ options,
527
+ tokenEndpoint: "https://id.twitch.tv/oauth2/token"
528
+ });
529
+ },
560
530
  async getUserInfo(token) {
561
- const { data: profile, error: error2 } = await betterFetch6(
531
+ const { data: profile, error: error2 } = await betterFetch(
562
532
  "https://api.twitch.tv/helix/users",
563
533
  {
564
534
  method: "GET",
565
535
  headers: {
566
- Authorization: `Bearer ${token.accessToken}`
536
+ Authorization: `Bearer ${token.accessToken()}`
567
537
  }
568
538
  }
569
539
  );
@@ -583,19 +553,11 @@ var twitch = ({
583
553
  }
584
554
  };
585
555
  };
586
-
587
- // src/social-providers/twitter.ts
588
- import { betterFetch as betterFetch7 } from "@better-fetch/fetch";
589
- import { Twitter } from "arctic";
590
- var twitter = ({
591
- clientId,
592
- clientSecret,
593
- redirectURI
594
- }) => {
556
+ var twitter = (options) => {
595
557
  const twitterArctic = new Twitter(
596
- clientId,
597
- clientSecret,
598
- getRedirectURI("twitter", redirectURI)
558
+ options.clientId,
559
+ options.clientSecret,
560
+ getRedirectURI("twitter", options.redirectURI)
599
561
  );
600
562
  return {
601
563
  id: "twitter",
@@ -608,19 +570,22 @@ var twitter = ({
608
570
  _scopes
609
571
  );
610
572
  },
611
- validateAuthorizationCode: async (code, codeVerifier) => {
612
- if (!codeVerifier) {
613
- throw new BetterAuthError("codeVerifier is required for Twitter");
614
- }
615
- return twitterArctic.validateAuthorizationCode(code, codeVerifier);
573
+ validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
574
+ return validateAuthorizationCode({
575
+ code,
576
+ codeVerifier,
577
+ redirectURI: redirectURI || getRedirectURI("twitch", options.redirectURI),
578
+ options,
579
+ tokenEndpoint: "https://id.twitch.tv/oauth2/token"
580
+ });
616
581
  },
617
582
  async getUserInfo(token) {
618
- const { data: profile, error: error2 } = await betterFetch7(
583
+ const { data: profile, error: error2 } = await betterFetch(
619
584
  "https://api.x.com/2/users/me?user.fields=profile_image_url",
620
585
  {
621
586
  method: "GET",
622
587
  headers: {
623
- Authorization: `Bearer ${token.accessToken}`
588
+ Authorization: `Bearer ${token.accessToken()}`
624
589
  }
625
590
  }
626
591
  );
@@ -644,9 +609,6 @@ var twitter = ({
644
609
  };
645
610
  };
646
611
 
647
- // src/types/provider.ts
648
- import "arctic";
649
-
650
612
  // src/social-providers/index.ts
651
613
  var oAuthProviders = {
652
614
  apple,
@@ -659,17 +621,151 @@ var oAuthProviders = {
659
621
  twitter
660
622
  };
661
623
  var oAuthProviderList = Object.keys(oAuthProviders);
662
-
663
- // src/utils/state.ts
664
- import { generateState as generateStateOAuth } from "oslo/oauth2";
665
- function generateState(callbackURL, currentURL) {
666
- const code = generateStateOAuth();
667
- const state = `${code}!${callbackURL}!${currentURL}`;
624
+ function generateState(callbackURL, currentURL, dontRememberMe) {
625
+ const code = generateState$1();
626
+ const state = JSON.stringify({
627
+ code,
628
+ callbackURL,
629
+ currentURL,
630
+ dontRememberMe
631
+ });
668
632
  return { state, code };
669
633
  }
670
634
  function parseState(state) {
671
- const [code, callbackURL, currentURL] = state.split("!");
672
- return { code, callbackURL, currentURL };
635
+ const data = z.object({
636
+ code: z.string(),
637
+ callbackURL: z.string().optional(),
638
+ currentURL: z.string().optional(),
639
+ dontRememberMe: z.boolean().optional()
640
+ }).safeParse(JSON.parse(state));
641
+ return data;
642
+ }
643
+
644
+ // src/utils/date.ts
645
+ var getDate = (span, isSeconds = false) => {
646
+ const date = /* @__PURE__ */ new Date();
647
+ return new Date(date.getTime() + (isSeconds ? span * 1e3 : span));
648
+ };
649
+ function getCookies(options) {
650
+ const secure = !!options.advanced?.useSecureCookies || process.env.NODE_ENV === "production";
651
+ const secureCookiePrefix = secure ? "__Secure-" : "";
652
+ const cookiePrefix = "better-auth";
653
+ const sessionMaxAge = new TimeSpan(7, "d").seconds();
654
+ return {
655
+ sessionToken: {
656
+ name: `${secureCookiePrefix}${cookiePrefix}.session_token`,
657
+ options: {
658
+ httpOnly: true,
659
+ sameSite: "lax",
660
+ path: "/",
661
+ secure,
662
+ maxAge: sessionMaxAge
663
+ }
664
+ },
665
+ csrfToken: {
666
+ name: `${secureCookiePrefix ? "__Host-" : ""}${cookiePrefix}.csrf_token`,
667
+ options: {
668
+ httpOnly: true,
669
+ sameSite: "lax",
670
+ path: "/",
671
+ secure,
672
+ maxAge: 60 * 60 * 24 * 7
673
+ }
674
+ },
675
+ state: {
676
+ name: `${secureCookiePrefix}${cookiePrefix}.state`,
677
+ options: {
678
+ httpOnly: true,
679
+ sameSite: "lax",
680
+ path: "/",
681
+ secure,
682
+ maxAge: 60 * 15
683
+ // 15 minutes in seconds
684
+ }
685
+ },
686
+ pkCodeVerifier: {
687
+ name: `${secureCookiePrefix}${cookiePrefix}.pk_code_verifier`,
688
+ options: {
689
+ httpOnly: true,
690
+ sameSite: "lax",
691
+ path: "/",
692
+ secure,
693
+ maxAge: 60 * 15
694
+ // 15 minutes in seconds
695
+ }
696
+ },
697
+ dontRememberToken: {
698
+ name: `${secureCookiePrefix}${cookiePrefix}.dont_remember`,
699
+ options: {
700
+ httpOnly: true,
701
+ sameSite: "lax",
702
+ path: "/",
703
+ secure
704
+ //no max age so it expires when the browser closes
705
+ }
706
+ },
707
+ nonce: {
708
+ name: `${secureCookiePrefix}${cookiePrefix}.nonce`,
709
+ options: {
710
+ httpOnly: true,
711
+ sameSite: "lax",
712
+ path: "/",
713
+ secure,
714
+ maxAge: 60 * 15
715
+ // 15 minutes in seconds
716
+ }
717
+ }
718
+ };
719
+ }
720
+ function createCookieGetter(options) {
721
+ const secure = !!options.advanced?.useSecureCookies || process.env.NODE_ENV === "production";
722
+ const secureCookiePrefix = secure ? "__Secure-" : "";
723
+ const cookiePrefix = "better-auth";
724
+ function getCookie(cookieName, options2) {
725
+ return {
726
+ name: process.env.NODE_ENV === "production" ? `${secureCookiePrefix}${cookiePrefix}.${cookieName}` : `${cookiePrefix}.${cookieName}`,
727
+ options: {
728
+ secure,
729
+ sameSite: "lax",
730
+ path: "/",
731
+ maxAge: 60 * 15,
732
+ // 15 minutes in seconds
733
+ ...options2
734
+ }
735
+ };
736
+ }
737
+ return getCookie;
738
+ }
739
+ async function setSessionCookie(ctx, sessionToken, dontRememberMe, overrides) {
740
+ await ctx.setSignedCookie(
741
+ ctx.context.authCookies.sessionToken.name,
742
+ sessionToken,
743
+ ctx.context.secret,
744
+ dontRememberMe ? {
745
+ ...ctx.context.authCookies.sessionToken.options,
746
+ maxAge: void 0,
747
+ ...overrides
748
+ } : {
749
+ ...ctx.context.authCookies.sessionToken.options,
750
+ ...overrides
751
+ }
752
+ );
753
+ if (dontRememberMe) {
754
+ await ctx.setSignedCookie(
755
+ ctx.context.authCookies.dontRememberToken.name,
756
+ "true",
757
+ ctx.context.secret,
758
+ ctx.context.authCookies.dontRememberToken.options
759
+ );
760
+ }
761
+ }
762
+ function deleteSessionCookie(ctx) {
763
+ ctx.setCookie(ctx.context.authCookies.sessionToken.name, "", {
764
+ maxAge: 0
765
+ });
766
+ ctx.setCookie(ctx.context.authCookies.dontRememberToken.name, "", {
767
+ maxAge: 0
768
+ });
673
769
  }
674
770
 
675
771
  // src/api/routes/session.ts
@@ -680,45 +776,62 @@ var getSession = createAuthEndpoint(
680
776
  requireHeaders: true
681
777
  },
682
778
  async (ctx) => {
683
- const sessionCookieToken = await ctx.getSignedCookie(
684
- ctx.context.authCookies.sessionToken.name,
685
- ctx.context.secret
686
- );
687
- if (!sessionCookieToken) {
688
- return ctx.json(null, {
689
- status: 401
690
- });
691
- }
692
- const session = await ctx.context.internalAdapter.findSession(sessionCookieToken);
693
- if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) {
694
- ctx.setSignedCookie(
779
+ try {
780
+ const sessionCookieToken = await ctx.getSignedCookie(
695
781
  ctx.context.authCookies.sessionToken.name,
696
- "",
697
- ctx.context.secret,
698
- {
699
- maxAge: 0
782
+ ctx.context.secret
783
+ );
784
+ if (!sessionCookieToken) {
785
+ return ctx.json(null, {
786
+ status: 401
787
+ });
788
+ }
789
+ const session = await ctx.context.internalAdapter.findSession(sessionCookieToken);
790
+ if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) {
791
+ deleteSessionCookie(ctx);
792
+ if (session) {
793
+ await ctx.context.internalAdapter.deleteSession(session.session.id);
700
794
  }
795
+ return ctx.json(null, {
796
+ status: 401
797
+ });
798
+ }
799
+ const dontRememberMe = await ctx.getSignedCookie(
800
+ ctx.context.authCookies.dontRememberToken.name,
801
+ ctx.context.secret
701
802
  );
702
- return ctx.json(null, {
703
- status: 401
704
- });
705
- }
706
- const updatedSession = await ctx.context.internalAdapter.updateSession(
707
- session.session
708
- );
709
- await ctx.setSignedCookie(
710
- ctx.context.authCookies.sessionToken.name,
711
- updatedSession.id,
712
- ctx.context.secret,
713
- {
714
- ...ctx.context.authCookies.sessionToken.options,
715
- maxAge: updatedSession.expiresAt.valueOf() - Date.now()
803
+ if (dontRememberMe) {
804
+ return ctx.json(session);
716
805
  }
717
- );
718
- return ctx.json({
719
- session: updatedSession,
720
- user: session.user
721
- });
806
+ const expiresIn = ctx.context.session.expiresIn;
807
+ const updateAge = ctx.context.session.updateAge;
808
+ const sessionIsDueToBeUpdatedDate = session.session.expiresAt.valueOf() - expiresIn * 1e3 + updateAge * 1e3;
809
+ const shouldBeUpdated = sessionIsDueToBeUpdatedDate <= Date.now();
810
+ if (shouldBeUpdated) {
811
+ const updatedSession = await ctx.context.internalAdapter.updateSession(
812
+ session.session.id,
813
+ {
814
+ expiresAt: getDate(ctx.context.session.expiresIn, true)
815
+ }
816
+ );
817
+ if (!updatedSession) {
818
+ deleteSessionCookie(ctx);
819
+ return ctx.json(null, { status: 401 });
820
+ }
821
+ const maxAge = (updatedSession.expiresAt.valueOf() - Date.now()) / 1e3;
822
+ await setSessionCookie(ctx, updatedSession.id, false, {
823
+ maxAge
824
+ });
825
+ return ctx.json({
826
+ session: updatedSession,
827
+ user: session.user
828
+ });
829
+ }
830
+ return ctx.json(session);
831
+ } catch (error2) {
832
+ ctx.context.logger.error(error2);
833
+ return ctx.json(null, { status: 500 });
834
+ }
722
835
  }
723
836
  );
724
837
  var getSessionFromCtx = async (ctx) => {
@@ -736,22 +849,26 @@ var signInOAuth = createAuthEndpoint(
736
849
  {
737
850
  method: "POST",
738
851
  requireHeaders: true,
739
- query: z3.object({
852
+ query: z.object({
740
853
  /**
741
854
  * Redirect to the current URL after the
742
855
  * user has signed in.
743
856
  */
744
- currentURL: z3.string().optional()
857
+ currentURL: z.string().optional()
745
858
  }).optional(),
746
- body: z3.object({
859
+ body: z.object({
747
860
  /**
748
861
  * Callback URL to redirect to after the user has signed in.
749
862
  */
750
- callbackURL: z3.string().optional(),
863
+ callbackURL: z.string().optional(),
751
864
  /**
752
865
  * OAuth2 provider to use`
753
866
  */
754
- provider: z3.enum(oAuthProviderList)
867
+ provider: z.enum(oAuthProviderList),
868
+ /**
869
+ * If this is true the session will only be valid for the current browser session
870
+ */
871
+ dontRememberMe: z.boolean().default(false).optional()
755
872
  })
756
873
  },
757
874
  async (c) => {
@@ -765,7 +882,9 @@ var signInOAuth = createAuthEndpoint(
765
882
  provider: c.body.provider
766
883
  }
767
884
  );
768
- throw new APIError2("NOT_FOUND");
885
+ throw new APIError("NOT_FOUND", {
886
+ message: "Provider not found"
887
+ });
769
888
  }
770
889
  const cookie = c.context.authCookies;
771
890
  const currentURL = c.query?.currentURL ? new URL(c.query?.currentURL) : null;
@@ -791,6 +910,10 @@ var signInOAuth = createAuthEndpoint(
791
910
  state: state.state,
792
911
  codeVerifier
793
912
  });
913
+ url.searchParams.set(
914
+ "redirect_uri",
915
+ `${c.context.baseURL}/callback/${c.body.provider}`
916
+ );
794
917
  return {
795
918
  url: url.toString(),
796
919
  state: state.state,
@@ -798,7 +921,7 @@ var signInOAuth = createAuthEndpoint(
798
921
  redirect: true
799
922
  };
800
923
  } catch (e) {
801
- throw new APIError2("INTERNAL_SERVER_ERROR");
924
+ throw new APIError("INTERNAL_SERVER_ERROR");
802
925
  }
803
926
  }
804
927
  );
@@ -806,40 +929,42 @@ var signInEmail = createAuthEndpoint(
806
929
  "/sign-in/email",
807
930
  {
808
931
  method: "POST",
809
- body: z3.object({
810
- email: z3.string().email(),
811
- password: z3.string(),
812
- callbackURL: z3.string().optional(),
932
+ body: z.object({
933
+ email: z.string().email(),
934
+ password: z.string(),
935
+ callbackURL: z.string().optional(),
813
936
  /**
814
937
  * If this is true the session will only be valid for the current browser session
815
938
  * @default false
816
939
  */
817
- dontRememberMe: z3.boolean().default(false).optional()
940
+ dontRememberMe: z.boolean().default(false).optional()
818
941
  })
819
942
  },
820
943
  async (ctx) => {
821
944
  if (!ctx.context.options?.emailAndPassword?.enabled) {
822
945
  ctx.context.logger.error("Email and password is not enabled");
823
- throw new APIError2("BAD_REQUEST", {
946
+ throw new APIError("BAD_REQUEST", {
824
947
  message: "Email and password is not enabled"
825
948
  });
826
949
  }
827
950
  const currentSession = await getSessionFromCtx(ctx);
828
951
  if (currentSession) {
829
- return ctx.json({
830
- user: currentSession.user,
831
- session: currentSession.session,
832
- redirect: !!ctx.body.callbackURL,
833
- url: ctx.body.callbackURL
834
- });
952
+ await ctx.context.internalAdapter.deleteSession(
953
+ currentSession.session.id
954
+ );
835
955
  }
836
956
  const { email, password } = ctx.body;
837
- const argon2id = new Argon2id();
957
+ const checkEmail = z.string().email().safeParse(email);
958
+ if (!checkEmail.success) {
959
+ throw new APIError("BAD_REQUEST", {
960
+ message: "Invalid email"
961
+ });
962
+ }
838
963
  const user = await ctx.context.internalAdapter.findUserByEmail(email);
839
964
  if (!user) {
840
- await argon2id.hash(password);
965
+ await ctx.context.password.hash(password);
841
966
  ctx.context.logger.error("User not found", { email });
842
- throw new APIError2("UNAUTHORIZED", {
967
+ throw new APIError("UNAUTHORIZED", {
843
968
  message: "Invalid email or password"
844
969
  });
845
970
  }
@@ -848,37 +973,33 @@ var signInEmail = createAuthEndpoint(
848
973
  );
849
974
  if (!credentialAccount) {
850
975
  ctx.context.logger.error("Credential account not found", { email });
851
- throw new APIError2("UNAUTHORIZED", {
976
+ throw new APIError("UNAUTHORIZED", {
852
977
  message: "Invalid email or password"
853
978
  });
854
979
  }
855
980
  const currentPassword = credentialAccount?.password;
856
981
  if (!currentPassword) {
857
982
  ctx.context.logger.error("Password not found", { email });
858
- throw new APIError2("UNAUTHORIZED", {
983
+ throw new APIError("UNAUTHORIZED", {
859
984
  message: "Unexpected error"
860
985
  });
861
986
  }
862
- const validPassword = await argon2id.verify(currentPassword, password);
987
+ const validPassword = await ctx.context.password.verify(
988
+ currentPassword,
989
+ password
990
+ );
863
991
  if (!validPassword) {
864
992
  ctx.context.logger.error("Invalid password");
865
- throw new APIError2("UNAUTHORIZED", {
993
+ throw new APIError("UNAUTHORIZED", {
866
994
  message: "Invalid email or password"
867
995
  });
868
996
  }
869
997
  const session = await ctx.context.internalAdapter.createSession(
870
998
  user.user.id,
871
- ctx.request
872
- );
873
- await ctx.setSignedCookie(
874
- ctx.context.authCookies.sessionToken.name,
875
- session.id,
876
- ctx.context.secret,
877
- ctx.body.dontRememberMe ? {
878
- ...ctx.context.authCookies.sessionToken.options,
879
- maxAge: void 0
880
- } : ctx.context.authCookies.sessionToken.options
999
+ ctx.request,
1000
+ ctx.body.dontRememberMe
881
1001
  );
1002
+ await setSessionCookie(ctx, session.id, ctx.body.dontRememberMe);
882
1003
  return ctx.json({
883
1004
  user: user.user,
884
1005
  session,
@@ -887,31 +1008,80 @@ var signInEmail = createAuthEndpoint(
887
1008
  });
888
1009
  }
889
1010
  );
890
-
891
- // src/api/routes/callback.ts
892
- import { APIError as APIError3 } from "better-call";
893
- import { z as z4 } from "zod";
1011
+ z.object({
1012
+ id: z.string(),
1013
+ providerId: z.string(),
1014
+ accountId: z.string(),
1015
+ userId: z.string(),
1016
+ accessToken: z.string().nullable().optional(),
1017
+ refreshToken: z.string().nullable().optional(),
1018
+ idToken: z.string().nullable().optional(),
1019
+ accessTokenExpiresAt: z.date().nullable().optional(),
1020
+ refreshTokenExpiresAt: z.date().nullable().optional(),
1021
+ /**
1022
+ * Password is only stored in the credential provider
1023
+ */
1024
+ password: z.string().optional().nullable()
1025
+ });
1026
+ var userSchema = z.object({
1027
+ id: z.string(),
1028
+ email: z.string().transform((val) => val.toLowerCase()),
1029
+ emailVerified: z.boolean().default(false),
1030
+ name: z.string(),
1031
+ image: z.string().optional(),
1032
+ createdAt: z.date().default(/* @__PURE__ */ new Date()),
1033
+ updatedAt: z.date().default(/* @__PURE__ */ new Date())
1034
+ });
1035
+ z.object({
1036
+ id: z.string(),
1037
+ userId: z.string(),
1038
+ expiresAt: z.date(),
1039
+ ipAddress: z.string().optional(),
1040
+ userAgent: z.string().optional()
1041
+ });
1042
+ var generateId = () => {
1043
+ return generateRandomString(36, alphabet("a-z", "0-9"));
1044
+ };
894
1045
 
895
1046
  // src/client/client-utils.ts
896
1047
  var HIDE_ON_CLIENT_METADATA = {
897
1048
  onClient: "hide"
898
1049
  };
899
1050
 
900
- // src/utils/id.ts
901
- import { alphabet, generateRandomString } from "oslo/crypto";
902
- var generateId = () => {
903
- return generateRandomString(36, alphabet("a-z", "0-9"));
904
- };
905
-
1051
+ // src/utils/getAccount.ts
1052
+ function getAccountTokens(tokens) {
1053
+ const accessToken = tokens.accessToken();
1054
+ let refreshToken = void 0;
1055
+ try {
1056
+ refreshToken = tokens.refreshToken();
1057
+ } catch {
1058
+ }
1059
+ let accessTokenExpiresAt = void 0;
1060
+ let refreshTokenExpiresAt = void 0;
1061
+ try {
1062
+ accessTokenExpiresAt = tokens.accessTokenExpiresAt();
1063
+ } catch {
1064
+ }
1065
+ try {
1066
+ refreshTokenExpiresAt = tokens.refreshTokenExpiresAt();
1067
+ } catch {
1068
+ }
1069
+ return {
1070
+ accessToken,
1071
+ refreshToken,
1072
+ accessTokenExpiresAt,
1073
+ refreshTokenExpiresAt
1074
+ };
1075
+ }
1076
+
906
1077
  // src/api/routes/callback.ts
907
1078
  var callbackOAuth = createAuthEndpoint(
908
1079
  "/callback/:id",
909
1080
  {
910
1081
  method: "GET",
911
- query: z4.object({
912
- state: z4.string(),
913
- code: z4.string(),
914
- code_verifier: z4.string().optional()
1082
+ query: z.object({
1083
+ state: z.string(),
1084
+ code: z.string()
915
1085
  }),
916
1086
  metadata: HIDE_ON_CLIENT_METADATA
917
1087
  },
@@ -925,15 +1095,20 @@ var callbackOAuth = createAuthEndpoint(
925
1095
  c.params.id,
926
1096
  "not found"
927
1097
  );
928
- throw new APIError3("NOT_FOUND");
1098
+ throw new APIError("NOT_FOUND");
929
1099
  }
1100
+ const codeVerifier = await c.getSignedCookie(
1101
+ c.context.authCookies.pkCodeVerifier.name,
1102
+ c.context.secret
1103
+ );
930
1104
  const tokens = await provider.validateAuthorizationCode(
931
1105
  c.query.code,
932
- c.query.code_verifier || ""
1106
+ codeVerifier,
1107
+ `${c.context.baseURL}/callback/${provider.id}`
933
1108
  );
934
1109
  if (!tokens) {
935
1110
  c.context.logger.error("Code verification failed");
936
- throw new APIError3("UNAUTHORIZED");
1111
+ throw new APIError("UNAUTHORIZED");
937
1112
  }
938
1113
  const user = await provider.getUserInfo(tokens).then((res) => res?.user);
939
1114
  const id = generateId();
@@ -941,17 +1116,24 @@ var callbackOAuth = createAuthEndpoint(
941
1116
  ...user,
942
1117
  id
943
1118
  });
944
- const { callbackURL, currentURL } = parseState(c.query.state);
1119
+ const parsedState = parseState(c.query.state);
1120
+ if (!parsedState.success) {
1121
+ c.context.logger.error("Unable to parse state");
1122
+ throw new APIError("BAD_REQUEST", {
1123
+ message: "invalid state"
1124
+ });
1125
+ }
1126
+ const { callbackURL, currentURL, dontRememberMe } = parsedState.data;
945
1127
  if (!user || data.success === false) {
946
1128
  if (currentURL) {
947
1129
  throw c.redirect(`${currentURL}?error=oauth_validation_failed`);
948
1130
  } else {
949
- throw new APIError3("BAD_REQUEST");
1131
+ throw new APIError("BAD_REQUEST");
950
1132
  }
951
1133
  }
952
1134
  if (!callbackURL) {
953
1135
  c.context.logger.error("Callback URL not found");
954
- throw new APIError3("FORBIDDEN");
1136
+ throw new APIError("FORBIDDEN");
955
1137
  }
956
1138
  const dbUser = await c.context.internalAdapter.findUserByEmail(user.email);
957
1139
  const userId = dbUser?.user.id;
@@ -971,13 +1153,13 @@ var callbackOAuth = createAuthEndpoint(
971
1153
  accountId: user.id,
972
1154
  id: `${provider.id}:${user.id}`,
973
1155
  userId: dbUser.user.id,
974
- ...tokens
1156
+ ...getAccountTokens(tokens)
975
1157
  });
976
1158
  }
977
1159
  } else {
978
1160
  try {
979
1161
  await c.context.internalAdapter.createOAuthUser(data.data, {
980
- ...tokens,
1162
+ ...getAccountTokens(tokens),
981
1163
  id: `${provider.id}:${user.id}`,
982
1164
  providerId: provider.id,
983
1165
  accountId: user.id,
@@ -991,20 +1173,16 @@ var callbackOAuth = createAuthEndpoint(
991
1173
  }
992
1174
  }
993
1175
  if (!userId && !id)
994
- throw new APIError3("INTERNAL_SERVER_ERROR", {
1176
+ throw new APIError("INTERNAL_SERVER_ERROR", {
995
1177
  message: "Unable to create user"
996
1178
  });
997
1179
  const session = await c.context.internalAdapter.createSession(
998
1180
  userId || id,
999
- c.request
1181
+ c.request,
1182
+ dontRememberMe
1000
1183
  );
1001
1184
  try {
1002
- await c.setSignedCookie(
1003
- c.context.authCookies.sessionToken.name,
1004
- session.id,
1005
- c.context.secret,
1006
- c.context.authCookies.sessionToken.options
1007
- );
1185
+ await setSessionCookie(c, session.id, dontRememberMe);
1008
1186
  } catch (e) {
1009
1187
  c.context.logger.error("Unable to set session cookie", e);
1010
1188
  const url = new URL(currentURL || callbackURL);
@@ -1014,15 +1192,12 @@ var callbackOAuth = createAuthEndpoint(
1014
1192
  throw c.redirect(callbackURL);
1015
1193
  }
1016
1194
  );
1017
-
1018
- // src/api/routes/sign-out.ts
1019
- import { z as z5 } from "zod";
1020
1195
  var signOut = createAuthEndpoint(
1021
1196
  "/sign-out",
1022
1197
  {
1023
1198
  method: "POST",
1024
- body: z5.object({
1025
- callbackURL: z5.string().optional()
1199
+ body: z.object({
1200
+ callbackURL: z.string().optional()
1026
1201
  }).optional()
1027
1202
  },
1028
1203
  async (ctx) => {
@@ -1034,9 +1209,7 @@ var signOut = createAuthEndpoint(
1034
1209
  return ctx.json(null);
1035
1210
  }
1036
1211
  await ctx.context.internalAdapter.deleteSession(sessionCookieToken);
1037
- ctx.setCookie(ctx.context.authCookies.sessionToken.name, "", {
1038
- maxAge: 0
1039
- });
1212
+ deleteSessionCookie(ctx);
1040
1213
  return ctx.json(null, {
1041
1214
  body: {
1042
1215
  redirect: !!ctx.body?.callbackURL,
@@ -1045,22 +1218,15 @@ var signOut = createAuthEndpoint(
1045
1218
  });
1046
1219
  }
1047
1220
  );
1048
-
1049
- // src/api/routes/forget-password.ts
1050
- import { TimeSpan } from "oslo";
1051
- import { createJWT } from "oslo/jwt";
1052
- import { validateJWT } from "oslo/jwt";
1053
- import { Argon2id as Argon2id2 } from "oslo/password";
1054
- import { z as z6 } from "zod";
1055
1221
  var forgetPassword = createAuthEndpoint(
1056
1222
  "/forget-password",
1057
1223
  {
1058
1224
  method: "POST",
1059
- body: z6.object({
1225
+ body: z.object({
1060
1226
  /**
1061
1227
  * The email address of the user to send a password reset email to.
1062
1228
  */
1063
- email: z6.string().email()
1229
+ email: z.string().email()
1064
1230
  })
1065
1231
  },
1066
1232
  async (ctx) => {
@@ -1119,10 +1285,10 @@ var resetPassword = createAuthEndpoint(
1119
1285
  "/reset-password",
1120
1286
  {
1121
1287
  method: "POST",
1122
- body: z6.object({
1123
- token: z6.string(),
1124
- newPassword: z6.string(),
1125
- callbackURL: z6.string().optional()
1288
+ body: z.object({
1289
+ token: z.string(),
1290
+ newPassword: z.string(),
1291
+ callbackURL: z.string().optional()
1126
1292
  })
1127
1293
  },
1128
1294
  async (ctx) => {
@@ -1133,7 +1299,7 @@ var resetPassword = createAuthEndpoint(
1133
1299
  Buffer.from(ctx.context.secret),
1134
1300
  token
1135
1301
  );
1136
- const email = z6.string().email().parse(jwt.payload.email);
1302
+ const email = z.string().email().parse(jwt.payload.email);
1137
1303
  const user = await ctx.context.internalAdapter.findUserByEmail(email);
1138
1304
  if (!user) {
1139
1305
  return ctx.json(null, {
@@ -1153,8 +1319,7 @@ var resetPassword = createAuthEndpoint(
1153
1319
  }
1154
1320
  });
1155
1321
  }
1156
- const argon2id = new Argon2id2();
1157
- const hashedPassword = await argon2id.hash(newPassword);
1322
+ const hashedPassword = await ctx.context.password.hash(newPassword);
1158
1323
  const updatedUser = await ctx.context.internalAdapter.updatePassword(
1159
1324
  user.user.id,
1160
1325
  hashedPassword
@@ -1185,18 +1350,30 @@ var resetPassword = createAuthEndpoint(
1185
1350
  }
1186
1351
  }
1187
1352
  );
1188
-
1189
- // src/api/routes/verify-email.ts
1190
- import { TimeSpan as TimeSpan2 } from "oslo";
1191
- import { createJWT as createJWT2, validateJWT as validateJWT2 } from "oslo/jwt";
1192
- import { z as z7 } from "zod";
1353
+ async function createEmailVerificationToken(secret, email) {
1354
+ const token = await createJWT(
1355
+ "HS256",
1356
+ Buffer.from(secret),
1357
+ {
1358
+ email: email.toLowerCase()
1359
+ },
1360
+ {
1361
+ expiresIn: new TimeSpan(1, "h"),
1362
+ issuer: "better-auth",
1363
+ subject: "verify-email",
1364
+ audiences: [email],
1365
+ includeIssuedTimestamp: true
1366
+ }
1367
+ );
1368
+ return token;
1369
+ }
1193
1370
  var sendVerificationEmail = createAuthEndpoint(
1194
1371
  "/send-verification-email",
1195
1372
  {
1196
1373
  method: "POST",
1197
- body: z7.object({
1198
- email: z7.string().email(),
1199
- callbackURL: z7.string().optional()
1374
+ body: z.object({
1375
+ email: z.string().email(),
1376
+ callbackURL: z.string().optional()
1200
1377
  })
1201
1378
  },
1202
1379
  async (ctx) => {
@@ -1210,24 +1387,12 @@ var sendVerificationEmail = createAuthEndpoint(
1210
1387
  });
1211
1388
  }
1212
1389
  const { email } = ctx.body;
1213
- const token = await createJWT2(
1214
- "HS256",
1215
- Buffer.from(ctx.context.secret),
1216
- {
1217
- email: email.toLowerCase()
1218
- },
1219
- {
1220
- expiresIn: new TimeSpan2(1, "h"),
1221
- issuer: "better-auth",
1222
- subject: "verify-email",
1223
- audiences: [email],
1224
- includeIssuedTimestamp: true
1225
- }
1226
- );
1390
+ const token = await createEmailVerificationToken(ctx.context.secret, email);
1227
1391
  const url = `${ctx.context.baseURL}/verify-email?token=${token}?callbackURL=${ctx.body.callbackURL}`;
1228
1392
  await ctx.context.options.emailAndPassword.sendVerificationEmail(
1229
1393
  email,
1230
- url
1394
+ url,
1395
+ token
1231
1396
  );
1232
1397
  return ctx.json({
1233
1398
  status: true
@@ -1238,55 +1403,18 @@ var verifyEmail = createAuthEndpoint(
1238
1403
  "/verify-email",
1239
1404
  {
1240
1405
  method: "GET",
1241
- query: z7.object({
1242
- token: z7.string(),
1243
- callbackURL: z7.string()
1406
+ query: z.object({
1407
+ token: z.string(),
1408
+ callbackURL: z.string().optional()
1244
1409
  })
1245
1410
  },
1246
1411
  async (ctx) => {
1247
1412
  const { token } = ctx.query;
1413
+ let jwt;
1248
1414
  try {
1249
- const jwt = await validateJWT2(
1250
- "HS256",
1251
- Buffer.from(ctx.context.secret),
1252
- token
1253
- );
1254
- const schema = z7.object({
1255
- email: z7.string().email()
1256
- });
1257
- const parsed = schema.parse(jwt.payload);
1258
- const user = await ctx.context.internalAdapter.findUserByEmail(
1259
- parsed.email
1260
- );
1261
- if (!user) {
1262
- return ctx.json(null, {
1263
- status: 400,
1264
- statusText: "USER_NOT_FOUND",
1265
- body: {
1266
- message: "User not found"
1267
- }
1268
- });
1269
- }
1270
- const account = user.accounts.find((a) => a.providerId === "credential");
1271
- if (!account) {
1272
- return ctx.json(null, {
1273
- status: 400,
1274
- statusText: "ACCOUNT_NOT_FOUND",
1275
- body: {
1276
- message: "Account not found"
1277
- }
1278
- });
1279
- }
1280
- await ctx.context.internalAdapter.updateUserByEmail(parsed.email, {
1281
- emailVerified: true
1282
- });
1283
- if (ctx.query.callbackURL) {
1284
- throw ctx.redirect(ctx.query.callbackURL);
1285
- }
1286
- return ctx.json({
1287
- status: true
1288
- });
1415
+ jwt = await validateJWT("HS256", Buffer.from(ctx.context.secret), token);
1289
1416
  } catch (e) {
1417
+ ctx.context.logger.error("Failed to verify email", e);
1290
1418
  return ctx.json(null, {
1291
1419
  status: 400,
1292
1420
  statusText: "INVALID_TOKEN",
@@ -1295,11 +1423,43 @@ var verifyEmail = createAuthEndpoint(
1295
1423
  }
1296
1424
  });
1297
1425
  }
1426
+ const schema = z.object({
1427
+ email: z.string().email()
1428
+ });
1429
+ const parsed = schema.parse(jwt.payload);
1430
+ const user = await ctx.context.internalAdapter.findUserByEmail(
1431
+ parsed.email
1432
+ );
1433
+ if (!user) {
1434
+ return ctx.json(null, {
1435
+ status: 400,
1436
+ statusText: "USER_NOT_FOUND",
1437
+ body: {
1438
+ message: "User not found"
1439
+ }
1440
+ });
1441
+ }
1442
+ const account = user.accounts.find((a) => a.providerId === "credential");
1443
+ if (!account) {
1444
+ return ctx.json(null, {
1445
+ status: 400,
1446
+ statusText: "ACCOUNT_NOT_FOUND",
1447
+ body: {
1448
+ message: "Account not found"
1449
+ }
1450
+ });
1451
+ }
1452
+ await ctx.context.internalAdapter.updateUserByEmail(parsed.email, {
1453
+ emailVerified: true
1454
+ });
1455
+ if (ctx.query.callbackURL) {
1456
+ throw ctx.redirect(ctx.query.callbackURL);
1457
+ }
1458
+ return ctx.json({
1459
+ status: true
1460
+ });
1298
1461
  }
1299
1462
  );
1300
-
1301
- // src/api/routes/csrf.ts
1302
- import { alphabet as alphabet2, generateRandomString as generateRandomString2 } from "oslo/crypto";
1303
1463
  var getCSRFToken = createAuthEndpoint(
1304
1464
  "/csrf",
1305
1465
  {
@@ -1316,9 +1476,9 @@ var getCSRFToken = createAuthEndpoint(
1316
1476
  csrfToken
1317
1477
  };
1318
1478
  }
1319
- const token = generateRandomString2(32, alphabet2("a-z", "0-9", "A-Z"));
1320
- const hash = await hs256(ctx.context.secret, token);
1321
- const cookie = `${token}!${hash}`;
1479
+ const token = generateRandomString(32, alphabet("a-z", "0-9", "A-Z"));
1480
+ const hash2 = await hs256(ctx.context.secret, token);
1481
+ const cookie = `${token}!${hash2}`;
1322
1482
  await ctx.setSignedCookie(
1323
1483
  ctx.context.authCookies.csrfToken.name,
1324
1484
  cookie,
@@ -1335,7 +1495,8 @@ var getCSRFToken = createAuthEndpoint(
1335
1495
  var ok = createAuthEndpoint(
1336
1496
  "/ok",
1337
1497
  {
1338
- method: "GET"
1498
+ method: "GET",
1499
+ metadata: HIDE_ON_CLIENT_METADATA
1339
1500
  },
1340
1501
  async (ctx) => {
1341
1502
  return ctx.json({
@@ -1346,27 +1507,23 @@ var ok = createAuthEndpoint(
1346
1507
  var welcome = createAuthEndpoint(
1347
1508
  "/welcome/ok",
1348
1509
  {
1349
- method: "GET"
1510
+ method: "GET",
1511
+ metadata: HIDE_ON_CLIENT_METADATA
1350
1512
  },
1351
1513
  async () => {
1352
1514
  return new Response("Welcome to Better Auth");
1353
1515
  }
1354
1516
  );
1355
-
1356
- // src/api/routes/sign-up.ts
1357
- import { alphabet as alphabet3, generateRandomString as generateRandomString3 } from "oslo/crypto";
1358
- import { Argon2id as Argon2id3 } from "oslo/password";
1359
- import { z as z8 } from "zod";
1360
1517
  var signUpEmail = createAuthEndpoint(
1361
1518
  "/sign-up/email",
1362
1519
  {
1363
1520
  method: "POST",
1364
- body: z8.object({
1365
- name: z8.string(),
1366
- email: z8.string().email(),
1367
- password: z8.string(),
1368
- image: z8.string().optional(),
1369
- callbackURL: z8.string().optional()
1521
+ body: z.object({
1522
+ name: z.string(),
1523
+ email: z.string().email(),
1524
+ password: z.string(),
1525
+ image: z.string().optional(),
1526
+ callbackURL: z.string().optional()
1370
1527
  })
1371
1528
  },
1372
1529
  async (ctx) => {
@@ -1387,9 +1544,8 @@ var signUpEmail = createAuthEndpoint(
1387
1544
  body: { message: "Password is too short" }
1388
1545
  });
1389
1546
  }
1390
- const argon2id = new Argon2id3();
1391
1547
  const dbUser = await ctx.context.internalAdapter.findUserByEmail(email);
1392
- const hash = await argon2id.hash(password);
1548
+ const hash2 = await ctx.context.password.hash(password);
1393
1549
  if (dbUser?.user) {
1394
1550
  return ctx.json(null, {
1395
1551
  status: 400,
@@ -1399,7 +1555,7 @@ var signUpEmail = createAuthEndpoint(
1399
1555
  });
1400
1556
  }
1401
1557
  const createdUser = await ctx.context.internalAdapter.createUser({
1402
- id: generateRandomString3(32, alphabet3("a-z", "0-9", "A-Z")),
1558
+ id: generateRandomString(32, alphabet("a-z", "0-9", "A-Z")),
1403
1559
  email: email.toLowerCase(),
1404
1560
  name,
1405
1561
  image,
@@ -1408,11 +1564,11 @@ var signUpEmail = createAuthEndpoint(
1408
1564
  updatedAt: /* @__PURE__ */ new Date()
1409
1565
  });
1410
1566
  await ctx.context.internalAdapter.linkAccount({
1411
- id: generateRandomString3(32, alphabet3("a-z", "0-9", "A-Z")),
1567
+ id: generateRandomString(32, alphabet("a-z", "0-9", "A-Z")),
1412
1568
  userId: createdUser.id,
1413
1569
  providerId: "credential",
1414
1570
  accountId: createdUser.id,
1415
- password: hash
1571
+ password: hash2
1416
1572
  });
1417
1573
  const session = await ctx.context.internalAdapter.createSession(
1418
1574
  createdUser.id,
@@ -1424,6 +1580,18 @@ var signUpEmail = createAuthEndpoint(
1424
1580
  ctx.context.secret,
1425
1581
  ctx.context.authCookies.sessionToken.options
1426
1582
  );
1583
+ if (ctx.context.options.emailAndPassword.sendEmailVerificationOnSignUp) {
1584
+ const token = await createEmailVerificationToken(
1585
+ ctx.context.secret,
1586
+ createdUser.email
1587
+ );
1588
+ const url = `${ctx.context.baseURL}/verify-email?token=${token}?callbackURL=${ctx.body.callbackURL}`;
1589
+ await ctx.context.options.emailAndPassword.sendVerificationEmail?.(
1590
+ createdUser.email,
1591
+ url,
1592
+ token
1593
+ );
1594
+ }
1427
1595
  return ctx.json(
1428
1596
  {
1429
1597
  user: createdUser,
@@ -1527,7 +1695,8 @@ var html = (errorCode = "Unknown") => `<!DOCTYPE html>
1527
1695
  var error = createAuthEndpoint(
1528
1696
  "/error",
1529
1697
  {
1530
- method: "GET"
1698
+ method: "GET",
1699
+ metadata: HIDE_ON_CLIENT_METADATA
1531
1700
  },
1532
1701
  async (c) => {
1533
1702
  const query = new URL(c.request?.url || "").searchParams.get("error") || "Unknown";
@@ -1540,7 +1709,7 @@ var error = createAuthEndpoint(
1540
1709
  );
1541
1710
 
1542
1711
  // src/api/index.ts
1543
- var router = (ctx) => {
1712
+ function getEndpoints(ctx, options) {
1544
1713
  const pluginEndpoints = ctx.options.plugins?.reduce(
1545
1714
  (acc, plugin) => {
1546
1715
  return {
@@ -1621,7 +1790,7 @@ var router = (ctx) => {
1621
1790
  }
1622
1791
  }
1623
1792
  }
1624
- const endpointRes = value({
1793
+ const endpointRes = await value({
1625
1794
  ...context,
1626
1795
  context: {
1627
1796
  ...ctx,
@@ -1635,7 +1804,10 @@ var router = (ctx) => {
1635
1804
  const match = hook.matcher(context);
1636
1805
  if (match) {
1637
1806
  const obj = Object.assign(context, {
1638
- returned: endpointRes
1807
+ context: {
1808
+ ...ctx,
1809
+ returned: response
1810
+ }
1639
1811
  });
1640
1812
  const hookRes = await hook.handler(obj);
1641
1813
  if (hookRes && "response" in hookRes) {
@@ -1652,9 +1824,17 @@ var router = (ctx) => {
1652
1824
  api[key].options = value.options;
1653
1825
  api[key].headers = value.headers;
1654
1826
  }
1827
+ return {
1828
+ api,
1829
+ middlewares
1830
+ };
1831
+ }
1832
+ var router = (ctx, _options) => {
1833
+ const { api, middlewares } = getEndpoints(ctx);
1834
+ const basePath = new URL(ctx.baseURL).pathname;
1655
1835
  return createRouter(api, {
1656
1836
  extraContext: ctx,
1657
- basePath: ctx.options.basePath,
1837
+ basePath,
1658
1838
  routerMiddleware: [
1659
1839
  {
1660
1840
  path: "/**",
@@ -1662,47 +1842,15 @@ var router = (ctx) => {
1662
1842
  },
1663
1843
  ...middlewares
1664
1844
  ],
1665
- /**
1666
- * this is to remove any sensitive data from the response
1667
- */
1668
- async transformResponse(res) {
1669
- let body = {};
1670
- try {
1671
- body = await res.json();
1672
- } catch (e) {
1673
- return res;
1674
- }
1675
- if (body?.user) {
1676
- body.user = parseUser(ctx.options, body.user);
1677
- }
1678
- if (body?.session) {
1679
- body.session = parseSession(ctx.options, body.session);
1680
- }
1681
- if (body?.account) {
1682
- body.account = parseAccount(ctx.options, body.account);
1683
- }
1684
- return new Response(body ? JSON.stringify(body) : null, {
1685
- headers: res.headers,
1686
- status: res.status,
1687
- statusText: res.statusText
1688
- });
1689
- },
1690
1845
  onError(e) {
1691
- console.log(e);
1846
+ if (e instanceof APIError) {
1847
+ if (e.status === "INTERNAL_SERVER_ERROR") {
1848
+ logger.error(e);
1849
+ }
1850
+ }
1692
1851
  }
1693
1852
  });
1694
1853
  };
1695
-
1696
- // src/adapters/kysely.ts
1697
- import Database from "better-sqlite3";
1698
- import { Kysely } from "kysely";
1699
- import {
1700
- MysqlDialect,
1701
- PostgresDialect,
1702
- SqliteDialect
1703
- } from "kysely";
1704
- import { createPool } from "mysql2";
1705
- import pg from "pg";
1706
1854
  var { Pool } = pg;
1707
1855
  function convertWhere(w) {
1708
1856
  if (!w)
@@ -1842,7 +1990,7 @@ var kyselyAdapter = (db, config) => {
1842
1990
  if (or) {
1843
1991
  query = query.where((eb) => eb.or(or));
1844
1992
  }
1845
- const res = await query.returningAll().executeTakeFirst();
1993
+ const res = await query.returningAll().executeTakeFirst() || null;
1846
1994
  if (config?.transform) {
1847
1995
  const schema = config.transform.schema[model];
1848
1996
  return schema ? transformTo(res, schema, config.transform) : res;
@@ -1867,10 +2015,13 @@ var getDialect = (config) => {
1867
2015
  if (!config.database) {
1868
2016
  return null;
1869
2017
  }
2018
+ if (config.database instanceof MysqlDialect || config.database instanceof PostgresDialect || config.database instanceof SqliteDialect) {
2019
+ return config.database;
2020
+ }
1870
2021
  let dialect = null;
1871
2022
  if ("provider" in config.database) {
1872
2023
  const provider = config.database.provider;
1873
- const connectionString = config.database.url.trim();
2024
+ const connectionString = config.database?.url?.trim();
1874
2025
  if (provider === "postgres") {
1875
2026
  const pool = new Pool({
1876
2027
  connectionString
@@ -2040,37 +2191,25 @@ function getAdapter(options) {
2040
2191
  if (!options.database) {
2041
2192
  throw new BetterAuthError("Database configuration is required");
2042
2193
  }
2043
- if ("provider" in options.database) {
2044
- const db = createKyselyAdapter(options);
2045
- if (!db) {
2046
- throw new BetterAuthError("Failed to initialize database adapter");
2047
- }
2048
- const tables = getAuthTables(options);
2049
- return kyselyAdapter(db, {
2050
- transform: {
2051
- schema: {
2052
- [tables.user.tableName]: tables.user.fields,
2053
- [tables.session.tableName]: tables.session.fields,
2054
- [tables.account.tableName]: tables.account.fields
2055
- },
2056
- date: true,
2057
- boolean: getDatabaseType(options) === "sqlite"
2058
- }
2059
- });
2194
+ const db = createKyselyAdapter(options);
2195
+ if (!db) {
2196
+ throw new BetterAuthError("Failed to initialize database adapter");
2060
2197
  }
2061
- return options.database;
2198
+ const tables = getAuthTables(options);
2199
+ return kyselyAdapter(db, {
2200
+ transform: {
2201
+ schema: {
2202
+ [tables.user.tableName]: tables.user.fields,
2203
+ [tables.session.tableName]: tables.session.fields,
2204
+ [tables.account.tableName]: tables.account.fields
2205
+ },
2206
+ date: true,
2207
+ boolean: getDatabaseType(options) === "sqlite"
2208
+ }
2209
+ });
2062
2210
  }
2063
-
2064
- // src/adapters/internal-adapter.ts
2065
- import { alphabet as alphabet4, generateRandomString as generateRandomString4 } from "oslo/crypto";
2066
-
2067
- // src/utils/date.ts
2068
- var getDate = (span) => {
2069
- const date = /* @__PURE__ */ new Date();
2070
- return new Date(date.getTime() + span);
2071
- };
2072
-
2073
- // src/adapters/internal-adapter.ts
2211
+ var hashPassword = argon2.hash;
2212
+ var verifyPassword = argon2.verify;
2074
2213
  var createInternalAdapter = (adapter, options) => {
2075
2214
  const sessionExpiration = options.session?.expiresIn || 60 * 60 * 24 * 7;
2076
2215
  const tables = getAuthTables(options);
@@ -2101,11 +2240,16 @@ var createInternalAdapter = (adapter, options) => {
2101
2240
  });
2102
2241
  return createdUser;
2103
2242
  },
2104
- createSession: async (userId, request) => {
2243
+ createSession: async (userId, request, dontRememberMe) => {
2105
2244
  const data = {
2106
- id: generateRandomString4(32, alphabet4("a-z", "0-9", "A-Z")),
2245
+ id: generateRandomString(32, alphabet("a-z", "0-9", "A-Z")),
2107
2246
  userId,
2108
- expiresAt: getDate(sessionExpiration),
2247
+ /**
2248
+ * If the user doesn't want to be remembered
2249
+ * set the session to expire in 1 day.
2250
+ * The cookie will be set to expire at the end of the session
2251
+ */
2252
+ expiresAt: dontRememberMe ? getDate(1e3 * 60 * 60 * 24) : getDate(sessionExpiration, true),
2109
2253
  ipAddress: request?.headers.get("x-forwarded-for") || "",
2110
2254
  userAgent: request?.headers.get("user-agent") || ""
2111
2255
  };
@@ -2145,39 +2289,18 @@ var createInternalAdapter = (adapter, options) => {
2145
2289
  user
2146
2290
  };
2147
2291
  },
2148
- updateSession: async (session) => {
2149
- const updateAge = options.session?.updateAge === void 0 ? 1e3 : options.session?.updateAge;
2150
- const updateDate = updateAge === 0 ? 0 : getDate(updateAge).valueOf();
2151
- const maxAge = getDate(sessionExpiration);
2152
- const shouldBeUpdated = session.expiresAt.valueOf() - maxAge.valueOf() + updateDate <= Date.now();
2153
- if (shouldBeUpdated) {
2154
- const updatedSession = await adapter.create({
2155
- model: tables.session.tableName,
2156
- data: {
2157
- ...session,
2158
- id: generateRandomString4(32, alphabet4("a-z", "0-9", "A-Z")),
2159
- expiresAt: new Date(Date.now() + sessionExpiration)
2160
- }
2161
- });
2162
- await adapter.update({
2163
- model: tables.session.tableName,
2164
- where: [
2165
- {
2166
- field: "id",
2167
- value: session.id
2168
- }
2169
- ],
2170
- update: {
2171
- /**
2172
- * update the session to expire in 2 minute. This is to prevent
2173
- * the session from expiring too quickly and logging the user out.
2174
- */
2175
- expiresAt: new Date(Date.now() + 1e3 * 60 * 2)
2292
+ updateSession: async (sessionId, session) => {
2293
+ const updatedSession = await adapter.update({
2294
+ model: tables.session.tableName,
2295
+ where: [
2296
+ {
2297
+ field: "id",
2298
+ value: sessionId
2176
2299
  }
2177
- });
2178
- return updatedSession;
2179
- }
2180
- return session;
2300
+ ],
2301
+ update: session
2302
+ });
2303
+ return updatedSession;
2181
2304
  },
2182
2305
  deleteSession: async (id) => {
2183
2306
  const session = await adapter.delete({
@@ -2278,144 +2401,37 @@ var createFieldAttribute = (type, config) => {
2278
2401
  };
2279
2402
  };
2280
2403
 
2281
- // src/utils/cookies.ts
2282
- import { TimeSpan as TimeSpan3 } from "oslo";
2283
- function getCookies(options) {
2284
- const secure = !!options.advanced?.useSecureCookies || process.env.NODE_ENV === "production";
2285
- const secureCookiePrefix = secure ? "__Secure-" : "";
2286
- const cookiePrefix = "better-auth";
2287
- const sessionMaxAge = new TimeSpan3(7, "d").seconds();
2288
- return {
2289
- sessionToken: {
2290
- name: `${secureCookiePrefix}${cookiePrefix}.session_token`,
2291
- options: {
2292
- httpOnly: true,
2293
- sameSite: "lax",
2294
- path: "/",
2295
- secure,
2296
- maxAge: sessionMaxAge
2297
- }
2298
- },
2299
- csrfToken: {
2300
- name: `${secureCookiePrefix ? "__Host-" : ""}${cookiePrefix}.csrf_token`,
2301
- options: {
2302
- httpOnly: true,
2303
- sameSite: "lax",
2304
- path: "/",
2305
- secure,
2306
- maxAge: 60 * 60 * 24 * 7
2307
- }
2308
- },
2309
- state: {
2310
- name: `${secureCookiePrefix}${cookiePrefix}.state`,
2311
- options: {
2312
- httpOnly: true,
2313
- sameSite: "lax",
2314
- path: "/",
2315
- secure,
2316
- maxAge: 60 * 15
2317
- // 15 minutes in seconds
2318
- }
2319
- },
2320
- pkCodeVerifier: {
2321
- name: `${secureCookiePrefix}${cookiePrefix}.pk_code_verifier`,
2322
- options: {
2323
- httpOnly: true,
2324
- sameSite: "lax",
2325
- path: "/",
2326
- secure,
2327
- maxAge: 60 * 15
2328
- // 15 minutes in seconds
2329
- }
2330
- },
2331
- nonce: {
2332
- name: `${secureCookiePrefix}${cookiePrefix}.nonce`,
2333
- options: {
2334
- httpOnly: true,
2335
- sameSite: "lax",
2336
- path: "/",
2337
- secure,
2338
- maxAge: 60 * 15
2339
- // 15 minutes in seconds
2340
- }
2341
- }
2342
- };
2343
- }
2344
- function createCookieGetter(options) {
2345
- const secure = !!options.advanced?.useSecureCookies || process.env.NODE_ENV === "production";
2346
- const secureCookiePrefix = secure ? "__Secure-" : "";
2347
- const cookiePrefix = "better-auth";
2348
- function getCookie(cookieName, options2) {
2349
- return {
2350
- name: process.env.NODE_ENV === "production" ? `${secureCookiePrefix}${cookiePrefix}.${cookieName}` : `${cookiePrefix}.${cookieName}`,
2351
- options: {
2352
- secure,
2353
- sameSite: "lax",
2354
- path: "/",
2355
- maxAge: 60 * 15,
2356
- // 15 minutes in seconds
2357
- ...options2
2358
- }
2359
- };
2360
- }
2361
- return getCookie;
2362
- }
2363
-
2364
- // src/utils/logger.ts
2365
- import { createConsola } from "consola";
2366
- var consola = createConsola({
2367
- formatOptions: {
2368
- date: false
2369
- }
2370
- });
2371
- var createLogger = (options) => {
2372
- return {
2373
- log: (...args) => {
2374
- !options?.disabled && consola.log("", ...args);
2375
- },
2376
- error: (...args) => {
2377
- !options?.disabled && consola.error("", ...args);
2378
- },
2379
- warn: (...args) => {
2380
- !options?.disabled && consola.warn("", ...args);
2381
- },
2382
- info: (...args) => {
2383
- !options?.disabled && consola.info("", ...args);
2384
- },
2385
- debug: (...args) => {
2386
- !options?.disabled && consola.debug("", ...args);
2387
- },
2388
- box: (...args) => {
2389
- !options?.disabled && consola.box("", ...args);
2390
- },
2391
- success: (...args) => {
2392
- !options?.disabled && consola.success("", ...args);
2393
- },
2394
- break: (...args) => {
2395
- !options?.disabled && console.log("\n");
2396
- }
2397
- };
2398
- };
2399
- var logger = createLogger();
2404
+ // src/utils/constants.ts
2405
+ var DEFAULT_SECRET = "better-auth-secret-123456789";
2400
2406
 
2401
2407
  // src/init.ts
2402
2408
  var init = (options) => {
2403
2409
  const adapter = getAdapter(options);
2404
2410
  const db = createKyselyAdapter(options);
2405
- const { baseURL, withPath: withPath2 } = getBaseURL(options.baseURL, options.basePath);
2411
+ const baseURL = getBaseURL(options.baseURL, options.basePath);
2406
2412
  return {
2407
2413
  options: {
2408
2414
  ...options,
2409
- baseURL,
2415
+ baseURL: baseURL ? new URL(baseURL).origin : "",
2410
2416
  basePath: options.basePath || "/api/auth"
2411
2417
  },
2412
- baseURL: withPath2,
2413
- secret: options.secret || process.env.BETTER_AUTH_SECRET || process.env.AUTH_SECRET || "better-auth-secret-123456789",
2418
+ baseURL: baseURL || "",
2419
+ session: {
2420
+ updateAge: options.session?.updateAge || 24 * 60 * 60,
2421
+ // 24 hours
2422
+ expiresIn: options.session?.expiresIn || 60 * 60 * 24 * 7
2423
+ // 7 days
2424
+ },
2425
+ secret: options.secret || process.env.BETTER_AUTH_SECRET || process.env.AUTH_SECRET || DEFAULT_SECRET,
2414
2426
  authCookies: getCookies(options),
2415
2427
  logger: createLogger({
2416
2428
  disabled: options.disableLog
2417
2429
  }),
2418
2430
  db,
2431
+ password: {
2432
+ hash: options.emailAndPassword?.password?.hash || hashPassword,
2433
+ verify: options.emailAndPassword?.password?.verify || verifyPassword
2434
+ },
2419
2435
  adapter,
2420
2436
  internalAdapter: createInternalAdapter(adapter, options),
2421
2437
  createAuthCookie: createCookieGetter(options)
@@ -2425,16 +2441,30 @@ var init = (options) => {
2425
2441
  // src/auth.ts
2426
2442
  var betterAuth = (options) => {
2427
2443
  const authContext = init(options);
2428
- const { handler, endpoints } = router(authContext);
2444
+ const { api } = getEndpoints(authContext);
2429
2445
  return {
2430
- handler,
2431
- api: endpoints,
2432
- options
2446
+ handler: async (request) => {
2447
+ const basePath = authContext.options.basePath;
2448
+ const url = new URL(request.url);
2449
+ if (!authContext.options.baseURL) {
2450
+ const baseURL = `${url.origin}/api/auth`;
2451
+ authContext.options.baseURL = baseURL;
2452
+ authContext.baseURL = baseURL;
2453
+ }
2454
+ if (!authContext.options.baseURL) {
2455
+ return new Response("Base URL not set", { status: 400 });
2456
+ }
2457
+ if (url.pathname === basePath || url.pathname === `${basePath}/`) {
2458
+ return new Response("Welcome to BetterAuth", { status: 200 });
2459
+ }
2460
+ const { handler } = router(authContext);
2461
+ return handler(request);
2462
+ },
2463
+ api,
2464
+ options: authContext.options
2433
2465
  };
2434
2466
  };
2435
- export {
2436
- betterAuth,
2437
- createFieldAttribute,
2438
- createInternalAdapter
2439
- };
2467
+
2468
+ export { betterAuth, createFieldAttribute, createInternalAdapter };
2469
+ //# sourceMappingURL=index.js.map
2440
2470
  //# sourceMappingURL=index.js.map