Openstatus www.openstatus.dev
at main 124 lines 3.9 kB view raw
1import type { DefaultSession } from "next-auth"; 2import NextAuth from "next-auth"; 3 4import { Events, setupAnalytics } from "@openstatus/analytics"; 5import { db, eq } from "@openstatus/db"; 6import { user } from "@openstatus/db/src/schema"; 7 8import { WelcomeEmail, sendEmail } from "@openstatus/emails"; 9import { headers } from "next/headers"; 10import { adapter } from "./adapter"; 11import { GitHubProvider, GoogleProvider, ResendProvider } from "./providers"; 12 13export type { DefaultSession }; 14 15export const { handlers, signIn, signOut, auth } = NextAuth({ 16 // debug: true, 17 adapter, 18 providers: 19 process.env.NODE_ENV === "development" || process.env.SELF_HOST === "true" 20 ? [GitHubProvider, GoogleProvider, ResendProvider] 21 : [GitHubProvider, GoogleProvider], 22 callbacks: { 23 async signIn(params) { 24 // We keep updating the user info when we loggin in 25 26 if (params.account?.provider === "google") { 27 if (!params.profile) return true; 28 if (Number.isNaN(Number(params.user.id))) return true; 29 30 await db 31 .update(user) 32 .set({ 33 firstName: params.profile.given_name, 34 lastName: params.profile.family_name || "", 35 photoUrl: params.profile.picture, 36 // keep the name in sync 37 name: `${params.profile.given_name} ${ 38 params.profile.family_name || "" 39 }`.trim(), 40 updatedAt: new Date(), 41 }) 42 .where(eq(user.id, Number(params.user.id))) 43 .run(); 44 } 45 if (params.account?.provider === "github") { 46 if (!params.profile) return true; 47 if (Number.isNaN(Number(params.user.id))) return true; 48 49 await db 50 .update(user) 51 .set({ 52 name: params.profile.name, 53 photoUrl: String(params.profile.avatar_url), 54 updatedAt: new Date(), 55 }) 56 .where(eq(user.id, Number(params.user.id))) 57 .run(); 58 } 59 60 // REMINDER: only used in dev mode 61 if (params.account?.provider === "resend") { 62 if (Number.isNaN(Number(params.user.id))) return true; 63 await db 64 .update(user) 65 .set({ updatedAt: new Date() }) 66 .where(eq(user.id, Number(params.user.id))) 67 .run(); 68 } 69 70 return true; 71 }, 72 async session(params) { 73 return params.session; 74 }, 75 }, 76 events: { 77 // That should probably done in the callback method instead 78 async createUser(params) { 79 if (!params.user.id || !params.user.email) { 80 throw new Error("User id & email is required"); 81 } 82 83 // this means the user has already been created with clerk 84 if (params.user.tenantId) return; 85 86 await sendEmail({ 87 from: "Thibault from OpenStatus <thibault@openstatus.dev>", 88 subject: "Welcome to OpenStatus.", 89 to: [params.user.email], 90 react: WelcomeEmail(), 91 }); 92 93 const analytics = await setupAnalytics({ 94 userId: `usr_${params.user.id}`, 95 email: params.user.email, 96 location: (await headers()).get("x-forwarded-for") ?? undefined, 97 userAgent: (await headers()).get("user-agent") ?? undefined, 98 }); 99 100 await analytics.track(Events.CreateUser); 101 }, 102 103 async signIn(params) { 104 if (params.isNewUser) return; 105 if (!params.user.id || !params.user.email) return; 106 107 const analytics = await setupAnalytics({ 108 userId: `usr_${params.user.id}`, 109 email: params.user.email, 110 location: (await headers()).get("x-forwarded-for") ?? undefined, 111 userAgent: (await headers()).get("user-agent") ?? undefined, 112 }); 113 114 await analytics.track(Events.SignInUser); 115 }, 116 }, 117 pages: { 118 signIn: "/login", 119 newUser: "/onboarding", 120 }, 121 // basePath: "/api/auth", // default is `/api/auth` 122 // secret: process.env.AUTH_SECRET, // default is `AUTH_SECRET` 123 debug: process.env.NODE_ENV === "development", 124});