Skip to content

Commit 7991bc7

Browse files
committed
require site url in cross domain plugin, improve react example
1 parent 25530ad commit 7991bc7

File tree

21 files changed

+891
-79
lines changed

21 files changed

+891
-79
lines changed

docs/app/page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,11 +664,15 @@ export default function Home() {
664664
type AuthFunctions,
665665
} from "@convex-dev/better-auth";
666666
import { convex, crossDomain } from "@convex-dev/better-auth/plugins";
667+
import { requireEnv } from "@convex-dev/better-auth/utils";
667668
import { betterAuth } from "better-auth";
668669
import { api, components, internal } from "./_generated/api";
669670
import { query, type GenericCtx } from "./_generated/server";
670671
import type { Id, DataModel } from "./_generated/dataModel";
671672
673+
// You'll want to replace this with an environment variable
674+
const siteUrl = "http://localhost:5173";
675+
672676
// Typesafe way to pass Convex functions defined in this file
673677
const authFunctions: AuthFunctions = internal.auth;
674678
@@ -683,6 +687,7 @@ export default function Home() {
683687
export const createAuth = (ctx: GenericCtx) =>
684688
// Configure your Better Auth instance here
685689
betterAuth({
690+
trustedOrigins: [siteUrl],
686691
database: convexAdapter(ctx, betterAuthComponent),
687692
688693
// Simple non-verified email/password to get started
@@ -696,7 +701,7 @@ export default function Home() {
696701
697702
// The cross domain plugin is required for client side frameworks
698703
crossDomain({
699-
siteUrl: "http://localhost:5173",
704+
siteUrl,
700705
}),
701706
],
702707
});

examples/next/convex/auth.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ import { convex } from "@convex-dev/better-auth/plugins";
88
import { api, components, internal } from "./_generated/api";
99
import { twoFactor } from "better-auth/plugins";
1010
import { emailOTP } from "better-auth/plugins";
11-
import { sendMagicLink, sendOTPVerification } from "./email";
12-
import { sendEmailVerification, sendResetPassword } from "./email";
11+
import {
12+
sendMagicLink,
13+
sendOTPVerification,
14+
sendEmailVerification,
15+
sendResetPassword,
16+
} from "./email";
1317
import { magicLink } from "better-auth/plugins";
1418
import { betterAuth } from "better-auth";
1519
import { GenericCtx, query } from "./_generated/server";

examples/react/convex/_generated/api.d.ts

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
*/
1010

1111
import type * as auth from "../auth.js";
12+
import type * as email from "../email.js";
13+
import type * as emails_components_BaseEmail from "../emails/components/BaseEmail.js";
14+
import type * as emails_magicLink from "../emails/magicLink.js";
15+
import type * as emails_resetPassword from "../emails/resetPassword.js";
16+
import type * as emails_verifyEmail from "../emails/verifyEmail.js";
17+
import type * as emails_verifyOTP from "../emails/verifyOTP.js";
1218
import type * as http from "../http.js";
1319
import type * as todos from "../todos.js";
1420
import type * as util from "../util.js";
@@ -29,6 +35,12 @@ import type {
2935
*/
3036
declare const fullApi: ApiFromModules<{
3137
auth: typeof auth;
38+
email: typeof email;
39+
"emails/components/BaseEmail": typeof emails_components_BaseEmail;
40+
"emails/magicLink": typeof emails_magicLink;
41+
"emails/resetPassword": typeof emails_resetPassword;
42+
"emails/verifyEmail": typeof emails_verifyEmail;
43+
"emails/verifyOTP": typeof emails_verifyOTP;
3244
http: typeof http;
3345
todos: typeof todos;
3446
util: typeof util;
@@ -54,14 +66,17 @@ export declare const components: {
5466
input:
5567
| {
5668
createdAt: number;
69+
displayUsername?: string;
5770
email: string;
5871
emailVerified: boolean;
5972
image?: string;
73+
isAnonymous?: boolean;
6074
name: string;
6175
table: string;
6276
twoFactorEnabled?: boolean;
6377
updatedAt: number;
64-
userId: string;
78+
userId?: string;
79+
username?: string;
6580
}
6681
| {
6782
createdAt: number;
@@ -88,12 +103,6 @@ export declare const components: {
88103
updatedAt: number;
89104
userId: string;
90105
}
91-
| {
92-
backupCodes: string;
93-
secret: string;
94-
table: string;
95-
userId: string;
96-
}
97106
| {
98107
createdAt?: number;
99108
expiresAt: number;
@@ -102,12 +111,23 @@ export declare const components: {
102111
updatedAt?: number;
103112
value: string;
104113
}
114+
| {
115+
backupCodes: string;
116+
secret: string;
117+
table: string;
118+
userId: string;
119+
}
105120
| {
106121
createdAt: number;
107-
id?: string;
108122
privateKey: string;
109123
publicKey: string;
110124
table: string;
125+
}
126+
| {
127+
count?: number;
128+
key?: string;
129+
lastRequest?: number;
130+
table: string;
111131
};
112132
},
113133
any
@@ -158,6 +178,12 @@ export declare const components: {
158178
{ expiresAt: number; userId: string },
159179
any
160180
>;
181+
deleteIn: FunctionReference<
182+
"mutation",
183+
"internal",
184+
{ input: { field: "token"; table: "session"; values: Array<string> } },
185+
any
186+
>;
161187
deleteOldVerifications: FunctionReference<
162188
"action",
163189
"internal",
@@ -186,12 +212,6 @@ export declare const components: {
186212
{ accountId: string; providerId: string },
187213
any
188214
>;
189-
getAccountsByUserId: FunctionReference<
190-
"query",
191-
"internal",
192-
{ limit?: number; userId: string },
193-
any
194-
>;
195215
getBy: FunctionReference<
196216
"query",
197217
"internal",
@@ -227,11 +247,41 @@ export declare const components: {
227247
any
228248
>;
229249
getCurrentSession: FunctionReference<"query", "internal", {}, any>;
250+
getIn: FunctionReference<
251+
"query",
252+
"internal",
253+
{
254+
input:
255+
| { field: "token"; table: "session"; values: Array<string> }
256+
| { field: "userId"; table: "user"; values: Array<string> };
257+
},
258+
any
259+
>;
230260
getJwks: FunctionReference<"query", "internal", { limit?: number }, any>;
231-
getSessionsByUserId: FunctionReference<
261+
listBy: FunctionReference<
232262
"query",
233263
"internal",
234-
{ limit?: number; userId: string },
264+
{
265+
input:
266+
| {
267+
field: "accountId" | "userId";
268+
limit?: number;
269+
table: "account";
270+
value: string;
271+
}
272+
| {
273+
field: "userId";
274+
limit?: number;
275+
table: "session";
276+
value: string;
277+
}
278+
| {
279+
field: "key";
280+
limit?: number;
281+
table: "rateLimit";
282+
value: string;
283+
};
284+
},
235285
any
236286
>;
237287
listVerificationsByIdentifier: FunctionReference<
@@ -308,12 +358,25 @@ export declare const components: {
308358
},
309359
any
310360
>;
311-
updateTwoFactor: FunctionReference<
361+
updateMany: FunctionReference<
312362
"mutation",
313363
"internal",
314364
{
315-
update: { backupCodes?: string; secret?: string; userId?: string };
316-
userId: string;
365+
input:
366+
| {
367+
field: "key";
368+
table: "rateLimit";
369+
update: { count?: number; key?: string; lastRequest?: number };
370+
}
371+
| {
372+
field: "userId";
373+
table: "twoFactor";
374+
update: {
375+
backupCodes?: string;
376+
secret?: string;
377+
userId?: string;
378+
};
379+
};
317380
},
318381
any
319382
>;

examples/react/convex/auth.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ import { GenericCtx, query } from "./_generated/server";
1010
import { requireEnv } from "./util";
1111
import { Id } from "./_generated/dataModel";
1212
import { asyncMap } from "convex-helpers";
13+
import { emailOTP } from "better-auth/plugins";
14+
import { magicLink } from "better-auth/plugins";
15+
import {
16+
sendMagicLink,
17+
sendOTPVerification,
18+
sendEmailVerification,
19+
sendResetPassword,
20+
} from "./email";
1321

1422
const authFunctions: AuthFunctions = internal.auth;
1523
const siteUrl = requireEnv("SITE_URL");
@@ -21,10 +29,25 @@ export const betterAuthComponent = new BetterAuth(components.betterAuth, {
2129

2230
export const createAuth = (ctx: GenericCtx) =>
2331
betterAuth({
32+
trustedOrigins: [siteUrl],
2433
database: convexAdapter(ctx, betterAuthComponent),
34+
emailVerification: {
35+
sendVerificationEmail: async ({ user, url }) => {
36+
await sendEmailVerification({
37+
to: user.email,
38+
url,
39+
});
40+
},
41+
},
2542
emailAndPassword: {
2643
enabled: true,
2744
requireEmailVerification: false,
45+
sendResetPassword: async ({ user, url }) => {
46+
await sendResetPassword({
47+
to: user.email,
48+
url,
49+
});
50+
},
2851
},
2952
socialProviders: {
3053
github: {
@@ -37,7 +60,26 @@ export const createAuth = (ctx: GenericCtx) =>
3760
enabled: true,
3861
},
3962
},
40-
plugins: [crossDomain({ siteUrl }), convex()],
63+
plugins: [
64+
magicLink({
65+
sendMagicLink: async ({ email, url }) => {
66+
await sendMagicLink({
67+
to: email,
68+
url,
69+
});
70+
},
71+
}),
72+
emailOTP({
73+
async sendVerificationOTP({ email, otp }) {
74+
await sendOTPVerification({
75+
to: email,
76+
code: otp,
77+
});
78+
},
79+
}),
80+
crossDomain({ siteUrl }),
81+
convex(),
82+
],
4183
logger: {
4284
level: "debug",
4385
},

examples/react/convex/email.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import "./polyfills";
2+
import { Resend } from "resend";
3+
import VerifyEmail from "./emails/verifyEmail";
4+
import MagicLinkEmail from "./emails/magicLink";
5+
import VerifyOTP from "./emails/verifyOTP";
6+
import { render } from "@react-email/components";
7+
import React from "react";
8+
import ResetPasswordEmail from "./emails/resetPassword";
9+
10+
const sendEmail = async ({
11+
to,
12+
subject,
13+
html,
14+
}: {
15+
to: string;
16+
subject: string;
17+
html: string;
18+
}) => {
19+
const resend = new Resend(process.env.RESEND_API_KEY);
20+
await resend.emails.send({
21+
from: "Test <[email protected]>",
22+
to: [to],
23+
subject,
24+
html,
25+
});
26+
};
27+
28+
export const sendEmailVerification = async ({
29+
to,
30+
url,
31+
}: {
32+
to: string;
33+
url: string;
34+
}) => {
35+
await sendEmail({
36+
to,
37+
subject: "Verify your email address",
38+
html: await render(<VerifyEmail url={url} />),
39+
});
40+
};
41+
42+
export const sendOTPVerification = async ({
43+
to,
44+
code,
45+
}: {
46+
to: string;
47+
code: string;
48+
}) => {
49+
await sendEmail({
50+
to,
51+
subject: "Verify your email address",
52+
html: await render(<VerifyOTP code={code} />),
53+
});
54+
};
55+
56+
export const sendMagicLink = async ({
57+
to,
58+
url,
59+
}: {
60+
to: string;
61+
url: string;
62+
}) => {
63+
await sendEmail({
64+
to,
65+
subject: "Sign in to your account",
66+
html: await render(<MagicLinkEmail url={url} />),
67+
});
68+
};
69+
70+
export const sendResetPassword = async ({
71+
to,
72+
url,
73+
}: {
74+
to: string;
75+
url: string;
76+
}) => {
77+
await sendEmail({
78+
to,
79+
subject: "Reset your password",
80+
html: await render(<ResetPasswordEmail url={url} />),
81+
});
82+
};

0 commit comments

Comments
 (0)