diff --git a/.env.example b/.env.example index 9cb7fa8..882a929 100644 --- a/.env.example +++ b/.env.example @@ -16,9 +16,5 @@ NEXTAUTH_URL="http://localhost:3000" # MongoDB Details DATABASE_URL= -# Next Auth Discord Provider -DISCORD_CLIENT_ID="" -DISCORD_CLIENT_SECRET="" - # Admin account details ADMIN_PASSWORD="password" \ No newline at end of file diff --git a/src/env.mjs b/src/env.mjs index 63b4be4..174ec54 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -18,9 +18,6 @@ const server = z.object({ // VERCEL_URL doesn't include `https` so it cant be validated as a URL process.env.VERCEL ? z.string().min(1) : z.string().url() ), - // Add `.min(1) on ID and SECRET if you want to make sure they're not empty - DISCORD_CLIENT_ID: z.string(), - DISCORD_CLIENT_SECRET: z.string(), }); /** diff --git a/src/server/auth.ts b/src/server/auth.ts index 7e6d826..0d140f1 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -4,10 +4,17 @@ import { type NextAuthOptions, type DefaultSession, } from "next-auth"; -import DiscordProvider from "next-auth/providers/discord"; +import CredentialsProvider from "next-auth/providers/credentials"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import { env } from "~/env.mjs"; import { prisma } from "~/server/db"; +import { loginSchema } from "~/lib/validation/auth"; +import { verify } from "argon2"; + +interface SessionUser { + id: string; + name: string; + username: string; +} /** * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` @@ -19,6 +26,7 @@ declare module "next-auth" { interface Session extends DefaultSession { user: { id: string; + username: string; // ...other properties // role: UserRole; } & DefaultSession["user"]; @@ -47,9 +55,39 @@ export const authOptions: NextAuthOptions = { }, adapter: PrismaAdapter(prisma), providers: [ - DiscordProvider({ - clientId: env.DISCORD_CLIENT_ID, - clientSecret: env.DISCORD_CLIENT_SECRET, + CredentialsProvider({ + // The name to display on the sign in form (e.g. 'Sign in with...') + name: "Credentials", + // The credentials is used to generate a suitable form on the sign in page. + // You can specify whatever fields you are expecting to be submitted. + // e.g. domain, username, password, 2FA token, etc. + // You can pass any HTML attribute to the tag through the object. + credentials: { + username: { label: "Username", type: "text" }, + password: { label: "Password", type: "password" }, + }, + async authorize(credentials): Promise { + // get the username and password from the credientials + const { username, password } = await loginSchema.parseAsync( + credentials + ); + + // check if username exists in the database + const result = await prisma.user.findFirst({ + where: { username }, + }); + if (!result) return null; + + // check if input password match the hashed password + const isValidPassword = await verify(result.password, password); + if (!isValidPassword) return null; + + return { + id: result.id, + name: result.name, + username, + }; + }, }), /** * ...add more providers here.