import NextAuth, { NextAuthOptions, Theme } from "next-auth"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; import prisma from "@/lib/db/prisma"; import EmailProvider from "next-auth/providers/email"; import GithubProvider from "next-auth/providers/github"; import GoogleProvider from "next-auth/providers/google"; import { createTransport } from "nodemailer"; export const authOptions: NextAuthOptions = { adapter: PrismaAdapter(prisma), providers: [ GithubProvider({ clientId: process.env.GITHUB_ID as string, clientSecret: process.env.GITHUB_SECRET as string, }), GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), EmailProvider({ server: process.env.EMAIL_SERVER, from: process.env.EMAIL_FROM, maxAge: 10 * 60, // 10min, 邮箱链接失效时间,默认24小时 async sendVerificationRequest({ identifier: email, url, provider, theme, }) { const { host } = new URL(url); const transport = createTransport(provider.server); const result = await transport.sendMail({ to: email, from: provider.from, subject: `You are logging in to Inke`, text: text({ url, host }), html: html({ url, host, theme }), }); const failed = result.rejected.concat(result.pending).filter(Boolean); if (failed.length) { throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`); } }, }), ], }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; /** *使用HTML body 代替正文内容 */ function html(params: { url: string; host: string; theme: Theme }) { const { url, host, theme } = params; const escapedHost = host.replace(/\./g, "​."); const brandColor = theme.brandColor || "#346df1"; const color = { background: "#f9f9f9", text: "#444", mainBackground: "#fff", buttonBackground: brandColor, buttonBorder: brandColor, buttonText: theme.buttonText || "#fff", }; return `
Welcome to Inke 🎉
Sign in now
Button click without response? Try open this link in your browser. If you did not request this email you can safely ignore it.
`; } /** 不支持HTML 的邮件客户端会显示下面的文本信息 */ function text({ url, host }: { url: string; host: string }) { return `Welcome to Inke! This is a magic link, click on it to log in ${url}\n`; }