diff --git a/frontend/src/auth/RequireAuth.tsx b/frontend/src/auth/RequireAuth.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..3556a624f9942e70ce74d0f447ce2f9ec2fceb58
--- /dev/null
+++ b/frontend/src/auth/RequireAuth.tsx
@@ -0,0 +1,15 @@
+import React, { FC } from "react";
+import { Navigate, useLocation } from "react-router-dom";
+import { useAuth } from "./auth.context";
+
+export const RequireAuth: FC<{ children: JSX.Element }> = ({ children }) => {
+ const { user } = useAuth();
+ const location = useLocation();
+
+ if (!user.isLoggedIn) {
+ return (
+
+ );
+ }
+ return children;
+};
diff --git a/frontend/src/auth/auth.context.tsx b/frontend/src/auth/auth.context.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..0d8bd6605d0e54225d9dcabe5e9cedabd0a13db2
--- /dev/null
+++ b/frontend/src/auth/auth.context.tsx
@@ -0,0 +1,49 @@
+import React, {
+ createContext,
+ FC,
+ ReactNode,
+ useContext,
+ useState,
+} from "react";
+import { IUser } from "../types";
+import { getLocalUser, handleLogin, handleLogout } from "./auth.helper";
+
+interface IAuthContext {
+ login: (email: string, password: string, cb?: VoidFunction) => Promise;
+ logout: (cb?: VoidFunction) => Promise;
+ user: IUser;
+}
+
+const AuthContext = createContext({
+ login: async () => {},
+ logout: async () => {},
+ user: { isLoggedIn: false },
+});
+
+export const AuthProvider: FC<{ children: ReactNode }> = ({ children }) => {
+ const [user, setUser] = useState(getLocalUser());
+
+ const login = async (
+ email: string,
+ password: string,
+ cb: VoidFunction = () => {}
+ ) => {
+ const user = await handleLogin(email, password);
+ setUser(user);
+ cb();
+ };
+
+ const logout = async (cb: VoidFunction = () => {}) => {
+ await handleLogout();
+ setUser({ ...user, isLoggedIn: false });
+ cb();
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useAuth = () => useContext(AuthContext);
diff --git a/frontend/src/auth/auth.helper.ts b/frontend/src/auth/auth.helper.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3bcdcc73f4dfc2a587b9a5147a34fdfef64c5d95
--- /dev/null
+++ b/frontend/src/auth/auth.helper.ts
@@ -0,0 +1,60 @@
+import { authApi } from "../apis";
+import { IUser } from "../types";
+
+const LOCAL_USER_INFO = "survey-user-info";
+
+/**
+ * 1. 백엔드 로그인을 호출하여 로그인 정보를 얻습니다.
+ * 2. 로컬 저장소에 저장합니다.
+ * 3. 사용자 정보를 반환합니다.
+ * @param email 이메일
+ * @param password 비밀번호
+ * @returns 사용자 정보
+ */
+export const handleLogin = async (email: string, password: string) => {
+ const user: IUser = await authApi.login(email, password);
+ // 로컬 저장소에는 로그인 여부만 저장
+ localStorage.setItem(
+ LOCAL_USER_INFO,
+ JSON.stringify({
+ isLoggedIn: user.isLoggedIn,
+ })
+ );
+ return user;
+};
+
+/**
+ * 로컬 저장소의 정보를 삭제합니다.
+ * 백엔드 로그아웃을 호출하여 쿠키를 제거합니다.
+ */
+export const handleLogout = async () => {
+ console.log("handle logout called");
+ localStorage.removeItem(LOCAL_USER_INFO);
+ try {
+ await authApi.logout();
+ } catch (error) {
+ console.log("logout 중에 에러 발생:", error);
+ }
+};
+
+/**
+ * 1. 로컬 저장소에 저장된 사용자 로그인 정보를 반환합니다.
+ * 2. 로컬 저장소에 정보가 없으면 { isLoggedIn: false }를 반환합니다.
+ * @returns 로컬 저장소에 저장된 사용자 정보
+ */
+export const getLocalUser = () => {
+ console.log("get local user called");
+ const userInfo = localStorage.getItem(LOCAL_USER_INFO);
+ const user: IUser = { isLoggedIn: false };
+ if (!userInfo) {
+ return user;
+ }
+
+ const userData = JSON.parse(userInfo);
+ if (userData.isLoggedIn) {
+ user.isLoggedIn = true;
+ } else {
+ user.isLoggedIn = false;
+ }
+ return user;
+};
diff --git a/frontend/src/types/index.tsx b/frontend/src/types/index.tsx
index 49f5d3af94043f5486e2195a465dbb0150a69f97..5c4c83562f904e95f19fefde582c98b2217c3c70 100644
--- a/frontend/src/types/index.tsx
+++ b/frontend/src/types/index.tsx
@@ -1,3 +1,9 @@
+export interface IUser {
+ email?: string;
+ isLoggedIn: boolean;
+ _id?: string;
+}
+
export interface PostType {
id: string;
title: string;