Files
GibSend/apps/web/src/server/auth.ts
2025-03-18 21:51:38 +11:00

132 lines
3.3 KiB
TypeScript

import { PrismaAdapter } from "@auth/prisma-adapter";
import {
getServerSession,
type DefaultSession,
type NextAuthOptions,
} from "next-auth";
import { type Adapter } from "next-auth/adapters";
import GitHubProvider from "next-auth/providers/github";
import EmailProvider from "next-auth/providers/email";
import GoogleProvider from "next-auth/providers/google";
import { Provider } from "next-auth/providers/index";
import { sendSignUpEmail } from "~/server/mailer";
import { env } from "~/env";
import { db } from "~/server/db";
/**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
* object and keep type safety.
*
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
*/
declare module "next-auth" {
// eslint-disable-next-line no-unused-vars
interface Session extends DefaultSession {
user: {
id: number;
isBetaUser: boolean;
isAdmin: boolean;
// ...other properties
// role: UserRole;
} & DefaultSession["user"];
}
// eslint-disable-next-line no-unused-vars
interface User {
id: number;
isBetaUser: boolean;
isAdmin: boolean;
}
}
/**
* Auth providers
*/
function getProviders() {
const providers: Provider[] = [];
if (env.GITHUB_ID && env.GITHUB_SECRET) {
providers.push(
GitHubProvider({
clientId: env.GITHUB_ID,
clientSecret: env.GITHUB_SECRET,
allowDangerousEmailAccountLinking: true,
})
);
}
if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
providers.push(
GoogleProvider({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
allowDangerousEmailAccountLinking: true,
})
);
}
if (env.FROM_EMAIL) {
providers.push(
EmailProvider({
from: env.FROM_EMAIL,
async sendVerificationRequest({ identifier: email, url, token }) {
await sendSignUpEmail(email, token, url);
},
async generateVerificationToken() {
return Math.random().toString(36).substring(2, 7).toLowerCase();
},
})
);
}
if (providers.length === 0 && process.env.SKIP_ENV_VALIDATION !== "true") {
throw new Error("No auth providers found, need atleast one");
}
return providers;
}
/**
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
*
* @see https://next-auth.js.org/configuration/options
*/
export const authOptions: NextAuthOptions = {
callbacks: {
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id,
isBetaUser: user.isBetaUser,
isAdmin: user.email === env.ADMIN_EMAIL,
},
}),
},
adapter: PrismaAdapter(db) as Adapter,
pages: {
signIn: "/login",
},
events: {
createUser: async ({ user }) => {
// No waitlist for self hosting
if (!env.NEXT_PUBLIC_IS_CLOUD || env.NODE_ENV === "development") {
await db.user.update({
where: { id: user.id },
data: { isBetaUser: true },
});
}
},
},
providers: getProviders(),
};
/**
* Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
*
* @see https://next-auth.js.org/configuration/nextjs
*/
export const getServerAuthSession = () => getServerSession(authOptions);