Skip to content

Commit 2c3573f

Browse files
authored
Merge pull request #46 from Security2431/fix/resend-next-auth-provider
fix: provide resend next-auth provider
2 parents a083d06 + e278c1a commit 2c3573f

File tree

8 files changed

+420
-445
lines changed

8 files changed

+420
-445
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ DATABASE_URL='postgres://[user]:[password]@[neon_hostname]/[dbname]?sslmode=requ
2222
# Email (Resend)
2323
# -----------------------------------------------------------------------------
2424
RESEND_API_KEY=
25+
EMAIL_FROM="SaaS Starter App <onboarding@resend.dev>"
2526

2627
# -----------------------------------------------------------------------------
2728
# Subscriptions (Stripe)

auth.config.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@ import Google from "next-auth/providers/google";
33
import Resend from "next-auth/providers/resend";
44

55
import { env } from "@/env.mjs";
6-
7-
// import { siteConfig } from "@/config/site"
8-
// import { getUserByEmail } from "@/lib/user";
9-
// import MagicLinkEmail from "@/emails/magic-link-email"
10-
// import { prisma } from "@/lib/db"
6+
import { sendVerificationRequest } from "@/lib/email";
117

128
export default {
139
providers: [
@@ -17,7 +13,8 @@ export default {
1713
}),
1814
Resend({
1915
apiKey: env.RESEND_API_KEY,
20-
from: "SaaS Starter App <onboarding@resend.dev>",
16+
from: env.EMAIL_FROM,
17+
sendVerificationRequest,
2118
}),
2219
],
2320
} satisfies NextAuthConfig;

content/docs/installation.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ GITHUB_OAUTH_TOKEN=
4747
DATABASE_URL=
4848

4949
RESEND_API_KEY=
50+
EMAIL_FROM=
5051

5152
STRIPE_API_KEY=
5253
STRIPE_WEBHOOK_SECRET=

emails/magic-link-email.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,27 @@ import {
44
Container,
55
Head,
66
Hr,
7-
Html, Preview,
7+
Html,
8+
Preview,
89
Section,
910
Tailwind,
10-
Text
11-
} from '@react-email/components';
12-
import { Icons } from '../components/shared/icons';
11+
Text,
12+
} from "@react-email/components";
13+
14+
import { Icons } from "../components/shared/icons";
1315

1416
type MagicLinkEmailProps = {
15-
actionUrl: string
16-
firstName: string
17-
mailType: "login" | "register"
18-
siteName: string
19-
}
17+
actionUrl: string;
18+
firstName: string;
19+
mailType: "login" | "register";
20+
siteName: string;
21+
};
2022

2123
export const MagicLinkEmail = ({
22-
firstName = '',
24+
firstName = "",
2325
actionUrl,
2426
mailType,
25-
siteName
27+
siteName,
2628
}: MagicLinkEmailProps) => (
2729
<Html>
2830
<Head />
@@ -33,11 +35,10 @@ export const MagicLinkEmail = ({
3335
<Body className="bg-white font-sans">
3436
<Container className="mx-auto py-5 pb-12">
3537
<Icons.logo className="m-auto block size-10" />
38+
<Text className="text-base">Hi {firstName},</Text>
3639
<Text className="text-base">
37-
Hi {firstName},
38-
</Text>
39-
<Text className="text-base">
40-
Welcome to {siteName} ! Click the link below to {mailType === "login" ? "sign in to" : "activate"} your account.
40+
Welcome to {siteName} ! Click the link below to{" "}
41+
{mailType === "login" ? "sign in to" : "activate"} your account.
4142
</Text>
4243
<Section className="my-5 text-center">
4344
<Button
@@ -52,7 +53,8 @@ export const MagicLinkEmail = ({
5253
</Text>
5354
{mailType === "login" ? (
5455
<Text className="text-base">
55-
If you did not try to log into your account, you can safely ignore it.
56+
If you did not try to log into your account, you can safely ignore
57+
it.
5658
</Text>
5759
) : null}
5860
<Hr className="my-4 border-t-2 border-gray-300" />
@@ -64,5 +66,3 @@ export const MagicLinkEmail = ({
6466
</Tailwind>
6567
</Html>
6668
);
67-
68-
export default MagicLinkEmail;

env.mjs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { createEnv } from "@t3-oss/env-nextjs"
2-
import { z } from "zod"
1+
import { createEnv } from "@t3-oss/env-nextjs";
2+
import { z } from "zod";
33

44
export const env = createEnv({
55
server: {
@@ -12,6 +12,7 @@ export const env = createEnv({
1212
GITHUB_OAUTH_TOKEN: z.string().min(1),
1313
DATABASE_URL: z.string().min(1),
1414
RESEND_API_KEY: z.string().min(1),
15+
EMAIL_FROM: z.string().min(1),
1516
STRIPE_API_KEY: z.string().min(1),
1617
STRIPE_WEBHOOK_SECRET: z.string().min(1),
1718
},
@@ -30,13 +31,18 @@ export const env = createEnv({
3031
GITHUB_OAUTH_TOKEN: process.env.GITHUB_OAUTH_TOKEN,
3132
DATABASE_URL: process.env.DATABASE_URL,
3233
RESEND_API_KEY: process.env.RESEND_API_KEY,
34+
EMAIL_FROM: process.env.EMAIL_FROM,
3335
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
3436
// Stripe
3537
STRIPE_API_KEY: process.env.STRIPE_API_KEY,
3638
STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
37-
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID: process.env.NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID,
38-
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID: process.env.NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID,
39-
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID: process.env.NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID,
40-
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID: process.env.NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID,
39+
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID:
40+
process.env.NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID,
41+
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID:
42+
process.env.NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID,
43+
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID:
44+
process.env.NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID,
45+
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID:
46+
process.env.NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID,
4147
},
42-
})
48+
});

lib/email.ts

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,51 @@
1+
import { MagicLinkEmail } from "@/emails/magic-link-email";
2+
import { EmailConfig } from "next-auth/providers/email";
13
import { Resend } from "resend";
24

35
import { env } from "@/env.mjs";
6+
import { siteConfig } from "@/config/site";
7+
8+
import { getUserByEmail } from "./user";
49

510
export const resend = new Resend(env.RESEND_API_KEY);
611

7-
// TODO: Update sendVerificationRequest for use react-email with resend magic-link
8-
9-
// Email({
10-
// sendVerificationRequest: async ({ identifier, url, provider }) => {
11-
// const user = await getUserByEmail(identifier);
12-
// if (!user || !user.name) return null;
13-
14-
// const userVerified = user?.emailVerified ? true : false;
15-
// const authSubject = userVerified ? `Sign-in link for ${siteConfig.name}` : "Activate your account";
16-
17-
// try {
18-
// const { data, error } = await resend.emails.send({
19-
// from: 'SaaS Starter App <onboarding@resend.dev>',
20-
// to: process.env.NODE_ENV === "development" ? 'delivered@resend.dev' : identifier,
21-
// subject: authSubject,
22-
// react: MagicLinkEmail({
23-
// firstName: user?.name as string,
24-
// actionUrl: url,
25-
// mailType: userVerified ? "login" : "register",
26-
// siteName: siteConfig.name
27-
// }),
28-
// // Set this to prevent Gmail from threading emails.
29-
// // More info: https://resend.com/changelog/custom-email-headers
30-
// headers: {
31-
// 'X-Entity-Ref-ID': new Date().getTime() + "",
32-
// },
33-
// });
34-
35-
// if (error || !data) {
36-
// throw new Error(error?.message)
37-
// }
38-
39-
// // console.log(data)
40-
// } catch (error) {
41-
// throw new Error("Failed to send verification email.")
42-
// }
43-
// },
44-
// }),
12+
export const sendVerificationRequest: EmailConfig["sendVerificationRequest"] =
13+
async ({ identifier, url, provider }) => {
14+
const user = await getUserByEmail(identifier);
15+
if (!user || !user.name) return;
16+
17+
const userVerified = user?.emailVerified ? true : false;
18+
const authSubject = userVerified
19+
? `Sign-in link for ${siteConfig.name}`
20+
: "Activate your account";
21+
22+
try {
23+
const { data, error } = await resend.emails.send({
24+
from: provider.from,
25+
to:
26+
process.env.NODE_ENV === "development"
27+
? "delivered@resend.dev"
28+
: identifier,
29+
subject: authSubject,
30+
react: MagicLinkEmail({
31+
firstName: user?.name as string,
32+
actionUrl: url,
33+
mailType: userVerified ? "login" : "register",
34+
siteName: siteConfig.name,
35+
}),
36+
// Set this to prevent Gmail from threading emails.
37+
// More info: https://resend.com/changelog/custom-email-headers
38+
headers: {
39+
"X-Entity-Ref-ID": new Date().getTime() + "",
40+
},
41+
});
42+
43+
if (error || !data) {
44+
throw new Error(error?.message);
45+
}
46+
47+
// console.log(data)
48+
} catch (error) {
49+
throw new Error("Failed to send verification email.");
50+
}
51+
};

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@radix-ui/react-toggle-group": "^1.1.0",
5050
"@radix-ui/react-tooltip": "^1.1.1",
5151
"@react-email/button": "0.0.15",
52-
"@react-email/components": "0.0.19",
52+
"@react-email/components": "0.0.21",
5353
"@react-email/html": "0.0.8",
5454
"@t3-oss/env-nextjs": "^0.10.1",
5555
"@typescript-eslint/parser": "^7.14.1",
@@ -64,18 +64,17 @@
6464
"lucide-react": "^0.381.0",
6565
"ms": "^2.1.3",
6666
"next": "14.2.4",
67-
"next-auth": "5.0.0-beta.18",
67+
"next-auth": "5.0.0-beta.19",
6868
"next-contentlayer2": "^0.4.6",
6969
"next-themes": "^0.3.0",
70-
"nodemailer": "^6.9.14",
7170
"prop-types": "^15.8.1",
7271
"react": "18.3.1",
7372
"react-day-picker": "^8.10.1",
7473
"react-dom": "18.3.1",
75-
"react-email": "2.1.4",
74+
"react-email": "2.1.5",
7675
"react-hook-form": "^7.52.0",
7776
"react-textarea-autosize": "^8.5.3",
78-
"resend": "^3.3.0",
77+
"resend": "^3.4.0",
7978
"sharp": "^0.33.4",
8079
"shiki": "^1.9.1",
8180
"sonner": "^1.5.0",

0 commit comments

Comments
 (0)