Skip to content

[✨ Feature] 카카오 간편 회원가입/ 로그인 연결 [✨ Feature] 로그인 회원가입 로직 alert 토스트 팝업으로 변경#212

Merged
eunji0124 merged 9 commits into
mainfrom
feat/195/kakao
Jan 17, 2026
Merged

[✨ Feature] 카카오 간편 회원가입/ 로그인 연결 [✨ Feature] 로그인 회원가입 로직 alert 토스트 팝업으로 변경#212
eunji0124 merged 9 commits into
mainfrom
feat/195/kakao

Conversation

@eunji0124
Copy link
Copy Markdown
Contributor

✅ PR 체크리스트

  • 기능 정상 동작
  • 콘솔 에러 없음
  • UI 동작 및 반응형 레이아웃 확인

🔗 이슈 번호

✨ 작업한 내용

  • 카카오 간편 로그인/회원가입 API 연결

  • 카카오 간편 로그인/회원가입 UI 추가

  • OAuth 인증 처리 로직 구현

  • 기존 alert()로 표시되던 로그인, 회원가입, OAuth, 마이페이지 저장 성공/실패 메시지를
    Toast 팝업으로 교체하여 UX 개선

  • 성공, 실패, 경고 메시지 타입에 따라 toast.success / toast.error / toast.warning 사용

💁 리뷰 요청 / 코멘트

💡 참고사항

@eunji0124 eunji0124 added this to the ✨ 페이지 기능 구현 milestone Jan 16, 2026
@eunji0124 eunji0124 self-assigned this Jan 16, 2026
@eunji0124 eunji0124 added the ✨ Feature 새로운 기능 구현 label Jan 16, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @eunji0124, 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!

이 PR은 카카오 소셜 로그인 및 회원가입 기능을 도입하여 사용자 인증 옵션을 확장합니다. 또한, 로그인, 회원가입, 마이페이지 등 주요 기능에서 기존의 alert() 메시지를 현대적인 토스트 알림으로 교체하여 사용자 경험을 크게 개선했습니다. 더불어, API 클라이언트에 강력한 토큰 리프레시 메커니즘을 통합하여 사용자 세션을 끊김 없이 유지할 수 있도록 했습니다.

Highlights

  • 카카오 간편 로그인/회원가입 연동: 카카오 OAuth를 이용한 로그인 및 회원가입 기능이 추가되었으며, 관련 API 엔드포인트와 UI가 구현되었습니다.
  • 토스트 알림으로 UX 개선: 기존 alert() 메시지를 로그인, 회원가입, 마이페이지 등 전반적인 사용자 흐름에서 toast.success, toast.error, toast.warning을 활용한 토스트 팝업으로 대체하여 사용자 경험을 향상시켰습니다.
  • 자동 토큰 리프레시 로직 구현: apiFetch 함수에 만료된 액세스 토큰을 자동으로 리프레시하는 로직이 추가되어, 사용자 세션의 연속성을 보장합니다.
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 by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request 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 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. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

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.

gemini-code-assist[bot]

This comment was marked as outdated.

@github-actions
Copy link
Copy Markdown

@eunji0124
Copy link
Copy Markdown
Contributor Author

/gemini review

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

이 PR은 카카오 소셜 로그인/회원가입 기능을 성공적으로 구현하고, 기존의 alert를 토스트 팝업으로 대체하여 사용자 경험을 개선했습니다. 또한 apiFetch에 토큰 자동 갱신 로직을 추가하여 세션 관리를 강화한 점도 좋습니다.

다만, 몇 가지 중요한 개선점이 필요해 보입니다:

  • 보안: 토큰이 localStorage에 저장되고 있어 XSS 공격에 취약합니다. 리프레시 토큰은 httpOnly 쿠키에, 액세스 토큰은 메모리에 저장하는 방식을 강력히 권장합니다.
  • 에러 처리: 에러 처리 로직이 API 에러 메시지 문자열에 의존하고 있어, 메시지가 변경될 경우 오작동할 수 있습니다. API 에러 코드를 사용하여 더 안정적으로 처리하는 것이 좋습니다.
  • 코드 일관성: API 응답에 대해 정의된 타입을 일관되게 사용하는 등 코드 품질을 높일 수 있는 부분이 있습니다.

자세한 내용은 각 파일에 남긴 개별 코멘트를 참고해 주세요.

Comment on lines 68 to 69
localStorage.setItem('accessToken', result.accessToken);
localStorage.setItem('refreshToken', result.refreshToken);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-critical critical

localStorage에 토큰을 저장하는 것은 XSS(Cross-Site Scripting) 공격에 취약할 수 있습니다. GENERAL_RULES에 따라, 리프레시 토큰은 httpOnly 쿠키에, 액세스 토큰은 메모리에 저장하는 방식을 고려해 보세요. 이는 보안을 크게 향상시킬 수 있습니다.

References
  1. Store refresh tokens in httpOnly cookies and access tokens in memory to mitigate XSS risks, instead of using localStorage.

Comment on lines +50 to +51
localStorage.setItem('accessToken', res.accessToken);
localStorage.setItem('refreshToken', res.refreshToken);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-critical critical

localStorage에 토큰을 저장하는 것은 XSS(Cross-Site Scripting) 공격에 취약합니다. 보안 강화를 위해 리프레시 토큰은 httpOnly 쿠키에, 액세스 토큰은 메모리에 저장하는 것이 좋습니다. 이는 저장소에 직접 접근하는 스크립팅 공격으로부터 토큰을 보호합니다.

References
  1. Store refresh tokens in httpOnly cookies and access tokens in memory to mitigate XSS risks, instead of using localStorage.

Comment on lines 94 to 112
if (error.message.includes('이메일')) {
setErrors((prev) => ({
...prev,
email: error.message,
}));
toast.error(error.message);
} else if (error.message.includes('닉네임')) {
setErrors((prev) => ({
...prev,
nickname: error.message,
}));
toast.error(error.message);
} else {
setErrors((prev) => ({
...prev,
password: error.message,
}));
toast.error(error.message);
}
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

에러 메시지 문자열(error.message.includes('이메일'))에 의존하여 분기하는 로직은 불안정합니다. API의 에러 메시지가 변경되면 로직이 깨질 수 있습니다. GENERAL_RULES에 따라, API 응답에 에러 코드나 에러 필드명을 포함하여 명시적으로 처리하는 것이 훨씬 안정적이고 유지보수하기 좋습니다. 예를 들어, 백엔드에서 { "code": "DUPLICATE_EMAIL", "field": "email", "message": "..." }와 같은 형식으로 응답을 내려주면 클라이언트에서 더 견고하게 처리할 수 있습니다.

References
  1. For robust error handling, use API error codes or dedicated field names for branching logic instead of relying on parsing error message strings.

Comment on lines +56 to +68
if (e instanceof Error) {
if (state === 'signup' && e.message.includes('이미')) {
toast.warning('이미 가입된 계정입니다. 로그인을 진행해 주세요.');
router.replace('/login');
} else if (state === 'login' && e.message.includes('않은')) {
toast.warning(
'가입되지 않은 계정입니다. 회원가입을 진행해 주세요.'
);
router.replace('/signup');
} else {
toast.error('인증에 실패했습니다. 다시 시도해주세요.');
router.replace(state === 'signup' ? '/signup' : '/login');
}
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

회원가입/로그인 실패 시 에러 메시지 문자열(e.message.includes('이미'))을 확인하여 분기하고 있습니다. 이 방식은 API의 에러 메시지가 변경될 경우 로직이 깨질 위험이 있습니다. GENERAL_RULES에서 권장하는 것처럼, 백엔드 API에서 명시적인 에러 코드(예: ALREADY_REGISTERED_USER, USER_NOT_FOUND)를 반환하도록 하여, 클라이언트에서는 이 코드를 기반으로 분기하는 것이 더 안정적입니다.

References
  1. For robust error handling, use API error codes or dedicated field names for branching logic instead of relying on parsing error message strings.

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.

/gemini
console.log('=== OAuth 에러 디버깅 ===');
console.log('에러 객체:', e);
console.log('에러 타입:', e?.constructor?.name);
console.log('에러 메시지:', e instanceof Error ? e.message : '');
console.log('상태 코드:', (e as any)?.statusCode);
console.log('상세 정보:', (e as any)?.details);

이렇게 테스트 해봤을때 아래처럼 떠서 글자 기준으로 분기했어 확인해줘

page.tsx:55_ 카카오 인증 실패 ApiError: 이미 등록된 사용자입니다. at apiFetch (client.ts:151:11) at async KakaoCallbackPage.useEffect.processOAuth (page.tsx:36:17)
page.tsx:58 === OAuth 에러 디버깅 ===
page.tsx:59 에러 객체: ApiError: 이미 등록된 사용자입니다. at apiFetch (client.ts:151:11) at async KakaoCallbackPage.useEffect.processOAuth (page.tsx:36:17)
page.tsx:60 에러 타입: ApiError
page.tsx:61 에러 메시지: 이미 등록된 사용자입니다.
page.tsx:62 상태 코드: undefined
page.tsx:63 상세 정보: undefined

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

eunji0124님, 디버깅 결과를 공유해주셔서 감사합니다. ApiError 객체에 statusCodedetails와 같은 명시적인 에러 코드가 포함되어 있지 않아 현재로서는 에러 메시지 문자열을 통해 분기하는 방식이 불가피하다는 점을 이해했습니다.

하지만 여전히 이 방식은 백엔드에서 에러 메시지 내용이 변경될 경우 클라이언트 로직이 오작동할 수 있는 위험을 내포하고 있습니다. 예를 들어, '이미 등록된 사용자입니다.'라는 메시지가 '이미 가입된 회원입니다.' 등으로 변경되면 현재 includes('이미') 로직은 더 이상 유효하지 않게 됩니다.

장기적인 관점에서 더 안정적이고 유지보수하기 쉬운 에러 처리를 위해서는 백엔드 API에서 ALREADY_REGISTERED_USER와 같은 명확한 에러 코드를 응답으로 제공하도록 개선하는 것을 강력히 권장합니다. 이를 통해 클라이언트에서는 문자열 비교 대신 에러 코드를 기반으로 정확하게 에러 상황을 판단하고 적절한 사용자 경험을 제공할 수 있습니다.

현재 상황에서는 이 로직이 최선일 수 있으나, 백엔드 팀과 협의하여 에러 응답 구조를 개선하는 방안을 고려해보시는 것이 좋겠습니다.

Comment thread src/api/auth.ts

// 토큰 리프레시 - POST /{teamId}/auth/tokens
export function refreshTokens(refreshToken: string) {
return apiFetch<{ accessToken: string; refreshToken: string }>(
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

refreshTokens 함수의 반환 타입을 인라인으로 정의하는 대신, src/types/auth.ts에 새로 추가된 RefreshTokenResponse 인터페이스를 사용하여 코드의 일관성과 유지보수성을 높이는 것이 좋습니다. import 문에도 RefreshTokenResponse를 추가해야 합니다.

Suggested change
return apiFetch<{ accessToken: string; refreshToken: string }>(
return apiFetch<RefreshTokenResponse>(
References
  1. For better code readability and intent, prefer using semantically specific types (e.g., UserResponse) over structurally identical but more generic ones (e.g., SignupResponse), even if they are aliases.

Comment on lines 115 to 118
setErrors((prev) => ({
...prev,
password: '알 수 없는 오류가 발생했습니다.',
}));
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

예상치 못한 에러가 발생했을 때, 에러 메시지를 password 필드에 할당하고 있습니다. 이 에러는 비밀번호와 관련이 없을 수 있으므로, 특정 필드에 할당하는 것은 사용자에게 혼란을 줄 수 있습니다. GENERAL_RULES에 따라, 이와 같은 일반적인 에러는 토스트 메시지로만 알리고 특정 입력 필드와 연결하지 않는 것이 좋습니다. setErrors 호출을 제거하는 것을 제안합니다.

References
  1. Handle generic, non-field-specific API errors with a global mechanism like a toast notification, rather than assigning the error to an arbitrary input field.

Comment thread src/app/oauth/kakao/KakaoCallbackContent.tsx Outdated
@github-actions
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@sylee86 sylee86 left a comment

Choose a reason for hiding this comment

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

카카오 회원가입,로그인 잘되는거 확인하였습니다. 수고하셨습니다!

@eunji0124 eunji0124 merged commit 68d279a into main Jan 17, 2026
1 check passed
@eunji0124 eunji0124 deleted the feat/195/kakao branch January 17, 2026 05:31
heyudin added a commit to heyudin/global-nomad that referenced this pull request Jan 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[✨ Feature] 로그인 회원가입 로직 alert 토스트 팝업으로 변경 [✨ Feature] 카카오 간편 회원가입/ 로그인 연결

2 participants