Jira: S15P11A705-309
증상
Google로 가입한 회원이 탈퇴해도 Google 계정의 「서드파티 앱 및 서비스」에 PinLog가 그대로 남는다. 실제로 확인했다. 다시 로그인하면 동의 화면 없이 통과한다 — S15P11A705-214가 없애려던 바로 그 상태다.
Kakao·Naver는 정상이다.
원인 — 200이 무엇의 성공인지 확인하지 않았다
서버는 access token을 POST https://oauth2.googleapis.com/revoke에 보내 200을 받고, 로그에 social account unlinked before withdrawal을 남긴다. 그 200은 토큰이 폐기됐다는 뜻이지 승인이 해제됐다는 뜻이 아니다.
Google에서 승인을 지우려면 refresh token을 폐기해야 하는데 우리는 받지 않는다 — 인가 요청이 scope: openid,email뿐이고 access_type=offline이 없다. 폐기 연쇄가 access → refresh 방향이라 refresh token이 없으면 연쇄할 대상도 없고 승인은 남는다.
BD-48 §①의 *"3사 모두 access token으로 해제할 수 있어 공급자별 분기가 없다"*가 Google에 대해 틀렸다. Kakao(/v1/user/unlink)와 Naver(/oauth2.0/revoke)는 연결 단위 API이고 Google만 토큰 단위다.
작업
- 탈퇴 왕복의 인가 요청에만
access_type=offline · prompt=consent를 붙인다(Google 전용, 로그인 진입 불변). WithdrawalAwareAuthorizationRequestResolver가 이미 탈퇴 왕복을 구분하고 있다. Google이 refresh token을 첫 인가에만 주므로 prompt=consent가 있어야 확실히 받는다.
- 콜백에서
OAuth2AuthorizedClient.getRefreshToken()을 꺼내 완료 단계로 전달한다 — 요청 범위 저장소가 이미 들고 있다.
GoogleUnlinkClient가 refresh token을 token으로 폐기하고, 없으면 access token으로 떨어진다.
- BD-48 §① 정정.
보관하지 않는다는 원칙은 그대로다. refresh token은 탈퇴 왕복의 토큰 교환 응답으로 와서 같은 요청 안에서 /revoke로 나가고 사라진다 — 지금 access token이 지나가는 경로와 같고 DB·Redis에 남지 않는다. BD-48 §①이 기각한 것은 로그인 시점에 받아 보관하는 안이다.
대가는 탈퇴 시 Google 동의 화면이 자동 통과 대신 실제로 뜨는 것이다. 계정 삭제 앞이라 명시적 승인이 오히려 맞다.
검증
관련
Jira: S15P11A705-309
증상
Google로 가입한 회원이 탈퇴해도 Google 계정의 「서드파티 앱 및 서비스」에 PinLog가 그대로 남는다. 실제로 확인했다. 다시 로그인하면 동의 화면 없이 통과한다 — S15P11A705-214가 없애려던 바로 그 상태다.
Kakao·Naver는 정상이다.
원인 — 200이 무엇의 성공인지 확인하지 않았다
서버는 access token을
POST https://oauth2.googleapis.com/revoke에 보내 200을 받고, 로그에social account unlinked before withdrawal을 남긴다. 그 200은 토큰이 폐기됐다는 뜻이지 승인이 해제됐다는 뜻이 아니다.Google에서 승인을 지우려면 refresh token을 폐기해야 하는데 우리는 받지 않는다 — 인가 요청이
scope: openid,email뿐이고access_type=offline이 없다. 폐기 연쇄가 access → refresh 방향이라 refresh token이 없으면 연쇄할 대상도 없고 승인은 남는다.BD-48 §①의 *"3사 모두 access token으로 해제할 수 있어 공급자별 분기가 없다"*가 Google에 대해 틀렸다. Kakao(
/v1/user/unlink)와 Naver(/oauth2.0/revoke)는 연결 단위 API이고 Google만 토큰 단위다.작업
access_type=offline·prompt=consent를 붙인다(Google 전용, 로그인 진입 불변).WithdrawalAwareAuthorizationRequestResolver가 이미 탈퇴 왕복을 구분하고 있다. Google이 refresh token을 첫 인가에만 주므로prompt=consent가 있어야 확실히 받는다.OAuth2AuthorizedClient.getRefreshToken()을 꺼내 완료 단계로 전달한다 — 요청 범위 저장소가 이미 들고 있다.GoogleUnlinkClient가 refresh token을token으로 폐기하고, 없으면 access token으로 떨어진다.보관하지 않는다는 원칙은 그대로다. refresh token은 탈퇴 왕복의 토큰 교환 응답으로 와서 같은 요청 안에서
/revoke로 나가고 사라진다 — 지금 access token이 지나가는 경로와 같고 DB·Redis에 남지 않는다. BD-48 §①이 기각한 것은 로그인 시점에 받아 보관하는 안이다.대가는 탈퇴 시 Google 동의 화면이 자동 통과 대신 실제로 뜨는 것이다. 계정 삭제 앞이라 명시적 승인이 오히려 맞다.
검증
GoogleUnlinkClient가 refresh token을 폐기하고 없으면 access token으로 떨어진다./gradlew clean check --no-daemon관련