소셜 로그인 전 경로(로그인 → 가입 → 계정 연결 → 세션 정리)를 훑어 어디까지 막혀 있는지를 전수로 정리한 표입니다. 2026-09-03 전수 점검으로 만들고 이후 변경을 반영해 왔습니다.

기준일 2026-09-10 · 총 48건

표기

기호 뜻
🟢 처리됨 + 실기기 확인
🔵 처리됨 + 코드 확인까지 (재현 조건을 만들기 어려움)
⚪ 의도적으로 처리하지 않음. 사유를 함께 적었다

분포

상태 건수
🟢 실기기 확인 15
🔵 코드 확인 30
⚪ 의도적 미처리 3
구간 건수
--- ---
1. SDK 단계 9
2. 서버 로그인 단계 9
3. 소셜 가입 단계 9
4. 계정 연결 단계 9
5. 세션 · 로그아웃 12

재현 조건을 만드는 것이 더 어려운 경우가 많아 코드 확인(🔵)이 절반 이상입니다. 나중에 어디를 다시 검증해야 하는지 알 수 있도록 실측과 코드 확인을 갈라 표시했습니다.


1. SDK 단계 — 토큰을 받기까지

엣지케이스 처리 위치 상태
사용자가 네이버 로그인을 취소 isCancel 과 Android user_cancel 코드를 둘 다 본다. 토스트를 띄우지 않는다 useNaverLogin.ts 🟢
사용자가 애플 로그인을 취소 애플은 취소 시 reject 한다. ERR_REQUEST_CANCELED 를 걸러 cancel 로 정규화 useAppleLogin.ts 🟢
네이버 SDK 가 실패 응답 isSuccess && successResponse 를 함께 확인해 failure 로 분기 useNaverLogin.ts 🔵
애플 identityToken 이 null 서버가 @NotBlank 라 400 이 난다. 보내지 않고 실패 토스트로 끝낸다 login.tsx 🔵
네이버 환경변수 미설정 IS_NAVER_LOGIN_CONFIGURED 로 초기화를 건너뛰고 안내 naverLogin.ts 🔵
애플 로그인 미지원 기기·OS isAvailableAsync() 결과로 버튼 자체를 숨긴다 login.tsx 🔵
버튼 연타 서버 왕복 중과 애플 SDK 진행 중에 버튼을 잠근다 login.tsx 🟢
네이버 앱에서 진행하지 않고 돌아옴 네이티브가 delegate 콜백이 와야 프로미스를 끝내므로 영영 pending 이다. 그 값으로 버튼을 잠그면 굳어버려 잠금 조건에서 뺐다. 네이티브가 대기를 매 호출마다 덮어써서 다시 눌러도 안전하다 login.tsx 🟢
iOS 시뮬레이터에서 네이버 로그인 지원하지 않는다. disableNaverAppAuthIOS: false 로 네이버 앱 인증을 쓰기 때문. 실기기로 테스트한다 naverLogin.ts ⚪

2. 서버 로그인 단계 — POST /auth/social-login

서버 경로는 5개입니다 — 이미 연결 / 30일 내 해제된 계정(재연결 후보) / 이메일 일치 + 검증됨 / 이메일 일치 + 미검증 / 매칭 없음(신규). 응답 형태는 2개(login, linkCandidate)뿐이고, profileRequired 는 서버가 주는 값이 아니라 앱이 hasProfile 로 갈라냅니다.

엣지케이스 처리 위치 상태
이미 연결된 계정 그대로 로그인. 앱은 라우팅하지 않고 Stack.Protected 에 맡긴다 useSocialLogin.ts 🟢
이메일 일치 + 소셜쪽 검증됨 서버가 자동 병합 후 로그인 서버 🟢
이메일 일치 + 소셜쪽 미검증 linkCandidate → 계정 연결 화면 login.tsx → link-social.tsx 🔵
신규 유저 profileRequired → 소셜 가입 화면. 토큰이 저장돼도 GUEST 라 me() 가 403 이므로 탭으로 튕기지 않는다 login.tsx → sns-signup/step1 🟢
소셜 토큰 무효·만료 INVALID_SOCIAL_LOGIN_TOKEN 을 분기해 "다시 시도해주세요" 로 안내 login.tsx 🔵
30일 이내 해제한 계정으로 재로그인 서버가 linkCandidate 로 돌려준다(2026-09-04 신규). 신규 가입이 아니라 연결 화면으로 간다 서버 🔵
maskedEmail 이 null 재연결 경로에서 이전 계정 이메일을 못 찾는 경우다. 이메일을 언급하지 않는 문구로 갈라 쓴다 link-social.tsx 🔵
네트워크 끊김 getNetworkErrorMessage 로 에러 코드보다 먼저 걸러낸다 login.tsx 🔵
그 외 서버 오류 일반 실패 토스트 login.tsx 🔵

3. 소셜 가입 단계 — POST /user/sns-sign-up

엣지케이스 처리 위치 상태
닉네임 중복 중복확인 버튼. nickname-check 는 permitAll 이라 GUEST 도 호출된다 sns-signup/step1 🟢
중복확인 후 닉네임을 고침 확인을 통과한 닉네임 문자열을 기억하고 현재 입력값과 비교한다. 값이 달라지면 확인 상태가 저절로 풀린다. 입력을 잠그지 않는다 sns-signup/step1 🔵
확인과 제출 사이에 선점당함 ALREADY_EXISTS_NICKNAME 을 분기하고 step1 로 되돌린다. 닉네임을 고치면 확인 상태가 풀리고 다시 확인할 수 있다 sns-signup/step2 🔵
termsId 가 실제와 다름 NOT_FOUND_TERMS 를 분기. 문구에 "약관" 을 남겨 로그만으로 원인을 알 수 있게 했다 sns-signup/step2 🔵
필수 약관 미동의 · 유형 미선택 버튼 disabled 로 제출 자체를 막는다 step1, step2 🟢
제출 중복 탭 isSigningUp 을 disabled 에 건다 sns-signup/step2 🔵
가입 도중 이탈 토큰을 지우지 않는다. 다시 소셜 로그인하면 서버가 hasProfile=false 를 주어 같은 화면으로 돌아온다 설계 🟢
가입 성공 후 라우팅 useSnsSignUp 이 새 USER 토큰으로 GUEST 토큰을 덮어쓰고 me() 를 invalidate 한다 useSnsSignUp.ts 🟢
네트워크 끊김 닉네임 확인·제출 양쪽에 판별 추가 step1, step2 🔵

⚠️ 2026-09-09 정정. 이전 판은 위 표의 "중복확인 후 닉네임을 고침" · "확인과 제출 사이에 선점당함" 두 줄을 "입력을 잠근다 / 돌아가면 잠금이 풀린다" 로 적었는데, 둘이 합쳐져 빠져나올 수 없는 상태를 만들고 있었습니다. 입력이 잠긴 채 중복확인 버튼도 같은 조건에서 비활성이라 닉네임을 바꿀 수단이 전부 사라졌고, 되돌아가도 이전 화면이 마운트된 채 남아 잠금이 풀리지 않았습니다. 실기기에서 가입이 막혀서 발견했습니다.

되돌아가면 상태가 초기화된다고 가정하지 않습니다.

4. 계정 연결 단계 — POST /auth/social-accounts/link

엣지케이스 처리 위치 상태
linkToken 5분 만료 EXPIRED_OR_INVALID_LINK_TOKEN → 안내 후 로그인 화면으로 되돌린다. 같은 토큰으로는 재시도해도 소용없다 link-social.tsx 🔵
그 사이 다른 계정에 연결됨 ALREADY_LINKED_SOCIAL_ACCOUNT → 안내 link-social.tsx 🔵
이 계정에 같은 provider 가 이미 연결됨 ALREADY_CONNECTED_PROVIDER → 안내. 2026-09-04 서버 변경으로 연결 확정 API 에도 이 검사가 붙었다 link-social.tsx 🔵
연결 대상이 이메일 미검증 계정 REQUIRED_EMAIL_VERIFICATION → 안내 link-social.tsx 🔵
본인 확인 로그인 실패 NOT_MATCH_USERNAME_PASSWORD 를 분기해 "이메일과 비밀번호를 확인해주세요" link-social.tsx 🔵
로그인은 됐는데 연결에서 실패 방금 저장한 토큰을 되돌린다. 로그인만 된 중간 상태로 들여보내면 왜 연결이 안 됐는지 모른 채 넘어간다 useLinkSocialAccount.ts 🔵
연결 도중 화면이 사라짐 로그인 → 연결 → me() invalidate 순서를 한 mutation 안에서 고정했다. 기존 로그인 훅을 그대로 쓰면 로그인 즉시 화면이 걷힌다 useLinkSocialAccount.ts 🔵
임시 비밀번호 계정 requirePasswordChange 면 기존 로그인과 동일하게 변경 화면으로 useLinkSocialAccount.ts 🔵
연결 화면 직접 진입 (linkToken 없음) 안내 후 되돌린다 link-social.tsx 🔵