@convex-dev/better-auth 0.6.1 → 0.7.0-alpha.0

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 (91) hide show
  1. package/README.md +8 -2
  2. package/dist/commonjs/client/adapter.d.ts.map +1 -1
  3. package/dist/commonjs/client/adapter.js +27 -9
  4. package/dist/commonjs/client/adapter.js.map +1 -1
  5. package/dist/commonjs/client/cors.d.ts +9 -4
  6. package/dist/commonjs/client/cors.d.ts.map +1 -1
  7. package/dist/commonjs/client/cors.js +44 -28
  8. package/dist/commonjs/client/cors.js.map +1 -1
  9. package/dist/commonjs/client/index.d.ts +1 -2
  10. package/dist/commonjs/client/index.d.ts.map +1 -1
  11. package/dist/commonjs/client/index.js +57 -61
  12. package/dist/commonjs/client/index.js.map +1 -1
  13. package/dist/commonjs/component/lib.d.ts +58 -0
  14. package/dist/commonjs/component/lib.d.ts.map +1 -1
  15. package/dist/commonjs/component/lib.js +28 -0
  16. package/dist/commonjs/component/lib.js.map +1 -1
  17. package/dist/commonjs/component/schema.d.ts +2 -0
  18. package/dist/commonjs/component/schema.d.ts.map +1 -1
  19. package/dist/commonjs/component/schema.js +3 -1
  20. package/dist/commonjs/component/schema.js.map +1 -1
  21. package/dist/commonjs/component/util.d.ts +6 -0
  22. package/dist/commonjs/component/util.d.ts.map +1 -1
  23. package/dist/commonjs/nextjs/index.d.ts.map +1 -1
  24. package/dist/commonjs/nextjs/index.js +3 -2
  25. package/dist/commonjs/nextjs/index.js.map +1 -1
  26. package/dist/commonjs/plugins/convex/index.d.ts +111 -2
  27. package/dist/commonjs/plugins/convex/index.d.ts.map +1 -1
  28. package/dist/commonjs/plugins/convex/index.js +66 -5
  29. package/dist/commonjs/plugins/convex/index.js.map +1 -1
  30. package/dist/commonjs/react-router/index.d.ts +10 -0
  31. package/dist/commonjs/react-router/index.d.ts.map +1 -0
  32. package/dist/commonjs/react-router/index.js +24 -0
  33. package/dist/commonjs/react-router/index.js.map +1 -0
  34. package/dist/commonjs/react-start/index.d.ts.map +1 -1
  35. package/dist/commonjs/react-start/index.js +2 -2
  36. package/dist/commonjs/react-start/index.js.map +1 -1
  37. package/dist/commonjs/util.d.ts +2 -0
  38. package/dist/commonjs/util.d.ts.map +1 -0
  39. package/dist/commonjs/util.js +8 -0
  40. package/dist/commonjs/util.js.map +1 -0
  41. package/dist/esm/client/adapter.d.ts.map +1 -1
  42. package/dist/esm/client/adapter.js +27 -9
  43. package/dist/esm/client/adapter.js.map +1 -1
  44. package/dist/esm/client/cors.d.ts +9 -4
  45. package/dist/esm/client/cors.d.ts.map +1 -1
  46. package/dist/esm/client/cors.js +44 -28
  47. package/dist/esm/client/cors.js.map +1 -1
  48. package/dist/esm/client/index.d.ts +1 -2
  49. package/dist/esm/client/index.d.ts.map +1 -1
  50. package/dist/esm/client/index.js +57 -61
  51. package/dist/esm/client/index.js.map +1 -1
  52. package/dist/esm/component/lib.d.ts +58 -0
  53. package/dist/esm/component/lib.d.ts.map +1 -1
  54. package/dist/esm/component/lib.js +28 -0
  55. package/dist/esm/component/lib.js.map +1 -1
  56. package/dist/esm/component/schema.d.ts +2 -0
  57. package/dist/esm/component/schema.d.ts.map +1 -1
  58. package/dist/esm/component/schema.js +3 -1
  59. package/dist/esm/component/schema.js.map +1 -1
  60. package/dist/esm/component/util.d.ts +6 -0
  61. package/dist/esm/component/util.d.ts.map +1 -1
  62. package/dist/esm/nextjs/index.d.ts.map +1 -1
  63. package/dist/esm/nextjs/index.js +3 -2
  64. package/dist/esm/nextjs/index.js.map +1 -1
  65. package/dist/esm/plugins/convex/index.d.ts +111 -2
  66. package/dist/esm/plugins/convex/index.d.ts.map +1 -1
  67. package/dist/esm/plugins/convex/index.js +66 -5
  68. package/dist/esm/plugins/convex/index.js.map +1 -1
  69. package/dist/esm/react-router/index.d.ts +10 -0
  70. package/dist/esm/react-router/index.d.ts.map +1 -0
  71. package/dist/esm/react-router/index.js +24 -0
  72. package/dist/esm/react-router/index.js.map +1 -0
  73. package/dist/esm/react-start/index.d.ts.map +1 -1
  74. package/dist/esm/react-start/index.js +2 -2
  75. package/dist/esm/react-start/index.js.map +1 -1
  76. package/dist/esm/util.d.ts +2 -0
  77. package/dist/esm/util.d.ts.map +1 -0
  78. package/dist/esm/util.js +8 -0
  79. package/dist/esm/util.js.map +1 -0
  80. package/package.json +1 -1
  81. package/src/client/adapter.ts +36 -11
  82. package/src/client/cors.ts +60 -38
  83. package/src/client/index.ts +65 -73
  84. package/src/component/_generated/api.d.ts +12 -0
  85. package/src/component/lib.ts +32 -0
  86. package/src/component/schema.ts +3 -1
  87. package/src/nextjs/index.ts +3 -2
  88. package/src/plugins/convex/index.ts +79 -11
  89. package/src/react-router/index.ts +31 -0
  90. package/src/react-start/index.ts +2 -2
  91. package/src/util.ts +7 -0
@@ -1,8 +1,4 @@
1
- import {
2
- createAuthMiddleware,
3
- getSession,
4
- sessionMiddleware,
5
- } from "better-auth/api";
1
+ import { createAuthMiddleware, sessionMiddleware } from "better-auth/api";
6
2
  import {
7
3
  BetterAuthPlugin,
8
4
  createAuthEndpoint,
@@ -14,10 +10,18 @@ import {
14
10
  import { omit } from "convex-helpers";
15
11
  import { z } from "zod";
16
12
 
17
- const JWT_COOKIE_NAME = "convex_jwt";
13
+ export const JWT_COOKIE_NAME = "convex_jwt";
18
14
 
19
- export const convex = (opts: { jwtExpirationSeconds?: number } = {}) => {
20
- const { jwtExpirationSeconds = 60 * 15 } = opts;
15
+ export const convex = (
16
+ opts: {
17
+ jwtExpirationSeconds?: number;
18
+ deleteExpiredSessionsOnLogin?: boolean;
19
+ } = {}
20
+ ) => {
21
+ const {
22
+ jwtExpirationSeconds = 60 * 15,
23
+ deleteExpiredSessionsOnLogin = false,
24
+ } = opts;
21
25
  const customSession = customSessionPlugin(async ({ user, session }) => {
22
26
  const { userId, ...userData } = omit(user, ["id"]) as typeof user & {
23
27
  userId: string;
@@ -54,8 +58,8 @@ export const convex = (opts: { jwtExpirationSeconds?: number } = {}) => {
54
58
  },
55
59
  });
56
60
  // Bearer plugin converts the session token to a cookie
57
- // for cross domain social login after code verification, and is required for
58
- // the headers() helper to work.
61
+ // for cross domain social login after code verification,
62
+ // and is required for the headers() helper to work.
59
63
  const bearer = bearerPlugin();
60
64
  const schema = {
61
65
  user: {
@@ -69,6 +73,70 @@ export const convex = (opts: { jwtExpirationSeconds?: number } = {}) => {
69
73
  before: [...bearer.hooks.before],
70
74
  after: [
71
75
  ...oidcProvider.hooks.after,
76
+ {
77
+ matcher: (ctx) => {
78
+ return (
79
+ deleteExpiredSessionsOnLogin &&
80
+ (ctx.path?.startsWith("/sign-in") ||
81
+ ctx.path?.startsWith("/callback"))
82
+ );
83
+ },
84
+ handler: createAuthMiddleware(async (ctx) => {
85
+ // Delete expired sessions at login
86
+ const userId = ctx.context.newSession?.user.id;
87
+ if (!userId) {
88
+ return;
89
+ }
90
+ await ctx.context.adapter.deleteMany({
91
+ model: "session",
92
+ where: [
93
+ {
94
+ field: "userId",
95
+ operator: "eq",
96
+ value: userId,
97
+ connector: "AND",
98
+ },
99
+ {
100
+ operator: "lte",
101
+ field: "expiresAt",
102
+ value: new Date().getTime(),
103
+ },
104
+ ],
105
+ });
106
+ }),
107
+ },
108
+ {
109
+ matcher: (ctx) => {
110
+ return (
111
+ ctx.path?.startsWith("/sign-in") ||
112
+ ctx.path?.startsWith("/callback")
113
+ );
114
+ },
115
+ handler: createAuthMiddleware(async (ctx) => {
116
+ // Set jwt cookie at login for ssa
117
+ const cookie = ctx.context.responseHeaders?.get("set-cookie") ?? "";
118
+ if (!cookie) {
119
+ return;
120
+ }
121
+ try {
122
+ const { token } = await jwt.endpoints.getToken({
123
+ ...ctx,
124
+ method: "GET",
125
+ headers: {
126
+ cookie,
127
+ },
128
+ returnHeaders: false,
129
+ });
130
+ const jwtCookie = ctx.context.createAuthCookie(JWT_COOKIE_NAME, {
131
+ maxAge: jwtExpirationSeconds,
132
+ });
133
+ ctx.setCookie(jwtCookie.name, token, jwtCookie.attributes);
134
+ } catch (err) {
135
+ // no-op, some sign-in calls (eg., when redirecting to 2fa)
136
+ // 401 here
137
+ }
138
+ }),
139
+ },
72
140
  {
73
141
  matcher: (ctx) => {
74
142
  return ctx.path?.startsWith("/sign-out");
@@ -137,7 +205,7 @@ export const convex = (opts: { jwtExpirationSeconds?: number } = {}) => {
137
205
  });
138
206
  return response;
139
207
  }
140
- ) as unknown as ReturnType<typeof getSession>,
208
+ ),
141
209
  getOpenIdConfig: createAuthEndpoint(
142
210
  "/convex/.well-known/openid-configuration",
143
211
  {
@@ -0,0 +1,31 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { createCookieGetter } from "better-auth/cookies";
3
+ import { GenericActionCtx } from "convex/server";
4
+ import { JWT_COOKIE_NAME } from "../plugins/convex";
5
+
6
+ export const getToken = async (
7
+ createAuth: (ctx: GenericActionCtx<any>) => ReturnType<typeof betterAuth>
8
+ ) => {
9
+ const { cookies } = await import("next/headers");
10
+ const cookieStore = await cookies();
11
+ const auth = createAuth({} as any);
12
+ const createCookie = createCookieGetter(auth.options);
13
+ const cookie = createCookie(JWT_COOKIE_NAME);
14
+ const token = cookieStore.get(cookie.name);
15
+ return token?.value;
16
+ };
17
+
18
+ const handler = (request: Request, opts?: { convexSiteUrl?: string }) => {
19
+ const requestUrl = new URL(request.url);
20
+ const convexSiteUrl =
21
+ opts?.convexSiteUrl ?? process.env.NEXT_PUBLIC_CONVEX_SITE_URL;
22
+ const nextUrl = `${convexSiteUrl}${requestUrl.pathname}${requestUrl.search}`;
23
+ const newRequest = new Request(nextUrl, request);
24
+ newRequest.headers.set("accept-encoding", "application/json");
25
+ return fetch(newRequest, { method: request.method, redirect: "manual" });
26
+ };
27
+
28
+ export const nextJsHandler = (opts?: { convexSiteUrl?: string }) => ({
29
+ GET: (request: Request) => handler(request, opts),
30
+ POST: (request: Request) => handler(request, opts),
31
+ });
@@ -2,13 +2,14 @@ import { betterAuth } from "better-auth";
2
2
  import { createCookieGetter } from "better-auth/cookies";
3
3
  import { betterFetch } from "@better-fetch/fetch";
4
4
  import { GenericActionCtx } from "convex/server";
5
+ import { JWT_COOKIE_NAME } from "../plugins/convex";
5
6
 
6
7
  export const getCookieName = async (
7
8
  createAuth: (ctx: GenericActionCtx<any>) => ReturnType<typeof betterAuth>
8
9
  ) => {
9
10
  const auth = createAuth({} as any);
10
11
  const createCookie = createCookieGetter(auth.options);
11
- const cookie = createCookie("convex_jwt");
12
+ const cookie = createCookie(JWT_COOKIE_NAME);
12
13
  return cookie.name;
13
14
  };
14
15
 
@@ -30,7 +31,6 @@ export const fetchSession = async <
30
31
  baseURL,
31
32
  headers: {
32
33
  cookie: request.headers.get("cookie") ?? "",
33
- origin: baseURL,
34
34
  },
35
35
  }
36
36
  );
package/src/util.ts ADDED
@@ -0,0 +1,7 @@
1
+ export const requireEnv = (name: string) => {
2
+ const value = process.env[name];
3
+ if (value === undefined) {
4
+ throw new Error(`Missing environment variable \`${name}\``);
5
+ }
6
+ return value;
7
+ };