

import { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import KakaoProvider from "next-auth/providers/kakao";
import NaverProvider from "next-auth/providers/naver";
import CredentialsProvider from "next-auth/providers/credentials";
import { findUserByEmail } from "@/services/user";
import bcrypt from "bcrypt";
async function verifyPassword(plainPassword: string, hashedPassword: string) {
return await bcrypt.compare(plainPassword, hashedPassword);
}
export const authOptions: NextAuthOptions = {
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
const { email, password } = credentials!;
const user = await findUserByEmail(email);
if (!user) return null;
const verifyPw = await verifyPassword(password, user.password);
if (!verifyPw) return null;
return {
id: user._id,
email: user.email,
name: user.name,
image: null,
username: user.email.split("@")[0],
};
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
}),
KakaoProvider({
clientId: process.env.KAKAO_CLIENT_ID || "",
clientSecret: process.env.KAKAO_CLIENT_SECRET || "",
}),
NaverProvider({
clientId: process.env.NAVER_CLIENT_ID || "",
clientSecret: process.env.NAVER_CLIENT_SECRET || "",
}),
],
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.username = `user_${user.id.slice(0, 8)}`;
}
return token;
},
async session({ session, token }) {
if (session.user) {
session.user.id = token.id;
session.user.username = token.username;
}
return session;
},
async redirect({ url, baseUrl }) {
// 로그인 후 리디렉션 설정
return baseUrl;
},
},
pages: {
signIn: "/auth/signin",
newUser: "/auth/signup",
},
};
3.sanity 함수 정의


"use client";
import { useRouter } from "next/navigation";
import { FormEvent, useRef } from "react";
type Props = {
csrfToken: string;
};
export default function SignupForm({ csrfToken }: Props) {
const usernameRef = useRef<HTMLInputElement>(null);
const emailRef = useRef<HTMLInputElement>(null);
const passRef = useRef<HTMLInputElement>(null);
const router = useRouter();
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const formData = new FormData();
formData.append("username", usernameRef.current?.value ?? "");
formData.append("email", emailRef.current?.value ?? "");
formData.append("password", passRef.current?.value ?? "");
fetch("/api/auth/signup", {
method: "POST",
body: formData,
}).then((res) => {
if (!res.ok) {
return console.log(`${res.status}${res.statusText}`);
}
router.push("/auth/signin");
});
};
return (
<form method="post" className="flex flex-col" onSubmit={handleSubmit}>
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<label>
이름
<input
name="username"
ref={usernameRef}
type="text"
className="border"
/>
</label>
<label>
이메일
<input name="email" ref={emailRef} type="email" className="border" />
</label>
<label>
비밀번호
<input
name="password"
ref={passRef}
type="password"
className="border"
/>
</label>
<button className="border" type="submit">
회원가입
</button>
</form>
);
}

import {
ClientSafeProvider,
getCsrfToken,
getProviders,
} from "next-auth/react";
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/lib/auth";
import { redirect } from "next/navigation";
import OAuthSignin from "@/components/OAuthSignin";
import CredentialSigninForm from "@/components/CredentialSigninForm";
type Providers = Record<string, ClientSafeProvider>;
export default async function SignInPage() {
const session = await getServerSession(authOptions);
const allProviders = ((await getProviders()) as Providers) ?? {};
const filteredProviders = Object.keys(allProviders).reduce((acc, key) => {
if (key !== "credentials") {
acc[key] = allProviders[key];
}
return acc;
}, {} as Providers);
const csrfToken = (await getCsrfToken()) ?? "";
if (session) {
redirect("/");
}
return (
<section>
<CredentialSigninForm csrfToken={csrfToken} />
<OAuthSignin providers={filteredProviders} />
</section>
);
}
. 로그인 후 리디렉션 설정
