Skip to content

Feat#97 Kakao Login oauth 구현#142

Merged
eunwoo-levi merged 8 commits into
mainfrom
feat#97
Jul 13, 2025
Merged

Feat#97 Kakao Login oauth 구현#142
eunwoo-levi merged 8 commits into
mainfrom
feat#97

Conversation

@eunwoo-levi
Copy link
Copy Markdown
Contributor

✅ Linked Issue

🔍 What I did

  • 카카오 소셜 로그인 인증 플로우 전체 구현
  • 인가 코드 콜백 처리 및 서버에서 accessToken을 HttpOnly 쿠키로 저장
  • 인증 성공/실패 UI 및 예외 처리
  • axios 인스턴스 withCredentials 적용

💡 Why I did it

  • 인증 토큰은 서버에서 HttpOnly 쿠키로 내려주어 XSS에 안전하게 관리
  • axios 인스턴스에 withCredentials: true 적용하여 쿠키 기반 인증 지원
  • 인증 실패 시 사용자에게 에러 메시지 노출 및 리다이렉트 처리

Oauth Flow

[사용자 브라우저]
   |
   | 1. 카카오 로그인 → 리디렉션 후 code 받음
   |
   | 2. code를 Next.js API Route (/api/oauth/kakao)로 전달
   v
[Next.js API Route]
   |
   | 3. 받은 code를 Spring 백엔드로 전달
   v
[백엔드]
   |
   | 4. 카카오 서버에 code → accessToken 교환
   | 5. accessToken으로 사용자 정보 조회 및 처리
   v
   → 성공 시 쿠키 or JWT 토큰 등 반환

🚧 TODO (if any)

  • 백엔드 플로우에 따라 추후 부분 변경될 예정

@vercel
Copy link
Copy Markdown

vercel Bot commented Jul 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
mosu-client ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 12, 2025 9:25am

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @eunwoo-levi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the complete Kakao social login functionality to the application. It establishes a secure authentication flow by handling authorization codes, exchanging them for access tokens, and storing these tokens as HttpOnly cookies. The changes span across the frontend and a new Next.js API route, ensuring a robust and user-friendly login experience with appropriate error handling and UI feedback.

Highlights

  • Kakao Social Login Implementation: I've implemented the full Kakao social login authentication flow, covering the user's redirection to Kakao, handling the authorization code callback, and processing it on the server side.
  • Secure Token Handling: The access token received from the backend after successful Kakao authentication is now securely stored as an HttpOnly cookie. This enhances security by mitigating Cross-Site Scripting (XSS) vulnerabilities.
  • Authentication Flow and UI Feedback: I've established a Next.js API route (/api/auth/kakao-auth-code) to act as an intermediary for the authorization code exchange with the backend. The frontend now includes dedicated pages and hooks to manage the authentication process, display loading states, and provide user-friendly error messages for both successful and failed login attempts.
  • Axios Configuration for Cookie-Based Auth: The global Axios instance (api.ts) has been configured with withCredentials: true. This ensures that cookies, including the HttpOnly access token, are automatically sent with cross-origin requests to support the cookie-based authentication mechanism.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jul 12, 2025

Messages
📖 ✅ PR 제목에 이슈 번호가 포함되어 있습니다.
📖 ✅ PR에 Reviewers가 지정되어 있습니다.
📖 ✅ PR에 라벨이 지정되어 있습니다.
📖 ✅ PR에 Assignees가 지정되어 있습니다.
📖 ✅ package.json에 변경사항이 없습니다.
📖 ✅ 브랜치 이름 'feat#97'이 컨벤션을 따릅니다.
📖 ✅ TypeScript 컴파일이 성공적으로 완료되었습니다.
📖 ✅ ESLint 검사 결과 문제가 없습니다.

📝 추가 및 변경된 파일

총 5개 파일 변경

├── 📂 mosu-admin/
│   └── 📂 src/
│       └── 📂 common/
│           └── 📂 lib/
│               └── 📘 api.ts
└── 📂 mosu-app/
    └── 📂 src/
        ├── 📂 pages/
        │   ├── 📂 auth/
        │   │   ├── 📂 member/
        │   │   │   └── ⚛️ signin.tsx
        │   │   └── 📂 kakao/
        │   │       └── ⚛️ callback.tsx
        │   └── 📂 api/
        │       └── 📂 auth/
        │           └── 📘 kakao-auth-code.ts
        └── 📂 features/
            └── 📂 auth-signin/
                └── 📂 hooks/
                    └── 📘 useKakaoAuth.ts

Generated by 🚫 dangerJS against 6ada039

@github-actions
Copy link
Copy Markdown

✅ Mosu Admin 빌드가 성공적으로 완료되었습니다!

📋 빌드 결과

  • ✅ DangerJS 검사 통과
  • ✅ React 앱 빌드 성공

🚀 다음 단계

코드 리뷰 후 머지하면 프로덕션에 배포됩니다.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the Kakao OAuth login flow. I've found a few critical and high-severity issues that need to be addressed, including a method mismatch in an API route, and unsafe access to environment variables. I've also included some suggestions to improve code quality and user experience.

Comment on lines +16 to +18
if (req.method !== "GET") {
return res.status(405).json({ message: "Method Not Allowed. Use GET." });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The API route is configured to only accept GET requests. However, the client-side useKakaoAuth hook sends a POST request. This will cause the request to fail with a 405 Method Not Allowed error. The handler should be updated to accept POST requests.

Suggested change
if (req.method !== "GET") {
return res.status(405).json({ message: "Method Not Allowed. Use GET." });
}
if (req.method !== "POST") {
return res.status(405).json({ message: "Method Not Allowed. Use POST." });
}

Comment on lines +20 to +23
const { code } = req.query;
if (!code || typeof code !== "string") {
return res.status(400).json({ message: "Authorization code is required." });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The API route is configured to read the authorization code from the query string (req.query). However, the client-side useKakaoAuth hook sends a POST request with the code in the request body. This will cause the request to fail. To fix this, read the code from req.body.

Suggested change
const { code } = req.query;
if (!code || typeof code !== "string") {
return res.status(400).json({ message: "Authorization code is required." });
}
const { code } = req.body;
if (!code || typeof code !== "string") {
return res.status(400).json({ message: "Authorization code is required." });
}

setError(null);
hasProcessedCode.current = code;

await api.post("/auth/kakao-auth-code", { code });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The API call is made to /auth/kakao-auth-code. However, Next.js API routes under pages/api/ are accessed with an /api prefix. The correct endpoint is /api/auth/kakao-auth-code.

Suggested change
await api.post("/auth/kakao-auth-code", { code });
await api.post("/api/auth/kakao-auth-code", { code });
router.push(redirectTo);

Comment on lines +15 to +18
const KAKAO_CLIENT_ID = process.env.NEXT_PUBLIC_KAKAO_REST_API_KEY!;
const REDIRECT_URI = process.env.NEXT_PUBLIC_KAKAO_REDIRECT_URI!;

const kakaoAuthUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using the non-null assertion operator (!) on environment variables is unsafe and can lead to runtime crashes if the variables are not set. A safer approach is to read the variables without assertion and then build the kakaoAuthUrl conditionally.

const KAKAO_CLIENT_ID = process.env.NEXT_PUBLIC_KAKAO_REST_API_KEY;
const REDIRECT_URI = process.env.NEXT_PUBLIC_KAKAO_REDIRECT_URI;

const kakaoAuthUrl =
    KAKAO_CLIENT_ID && REDIRECT_URI
        ? `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`
        : "";

잠시 후 다시 시도해주세요.
</p>
<button
onClick={() => window.location.href = "/auth/member/signin"}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For internal navigation within a Next.js application, it's better to use the useRouter hook's push method instead of window.location.href. This enables client-side routing, which avoids a full page reload and provides a smoother user experience.

onClick={() => router.push("/auth/member/signin")}

Comment on lines +36 to +40
return (
<div className="p-5 text-center">
<p>로그인 처리 중입니다...</p>
</div>
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The UI for the isLoading state and the default return state (which acts as a loading state before redirection) are identical. This leads to duplicated code. You can simplify this by combining the conditions.

if (isLoading || !error) {
    return (
        <div className="p-5 text-center">
            <p>로그인 처리 중입니다...</p>
        </div>
    );
}

return null;

@github-actions
Copy link
Copy Markdown

📚 Storybook이 Chromatic에 배포되었습니다!

Copy link
Copy Markdown
Contributor

@kimgho kimgho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oauth하느라 고생하셨습니다~

잠시 후 다시 시도해주세요.
</p>
<button
onClick={() => window.location.href = "/auth/member/signin"}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기에 window.location.href를 쓴 이유가 따로 있을까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kakao redirect로직 이어서 짜다가 당시에 무의식적으로 짠 것 같습니다. 해당 부분은 같은 도메인에서 이동하기 때문에 더 효율적인 라우팅을 위해 router를 쓰는게 낫겠네요! 짚어주셔서 감사합니다!

Comment on lines +18 to +19
const kakaoAuthUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가능하면 경로는 상수처리하는게 관리하기 편할거같아요~

Suggested change
const kakaoAuthUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`;
const kakaoAuthUrl = `NEXT_PUBLIC_KAKAO_REDIRECT_URI?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`;

@toothlessdev toothlessdev moved this to 진행중 in mosu-client Jul 13, 2025
Copy link
Copy Markdown
Member

@toothlessdev toothlessdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다 💯

@eunwoo-levi eunwoo-levi merged commit 3d99c54 into main Jul 13, 2025
23 checks passed
@github-project-automation github-project-automation Bot moved this from 진행중 to 완료 in mosu-client Jul 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 완료

Development

Successfully merging this pull request may close these issues.

[✨ 기능 요청] 카카오 로그인 oauth 구현

3 participants