네이버 oauth token revocation 오류 해결기 - Spring

윤희종·2025년 11월 17일

기술 블로그

목록 보기
1/11

안녕하세요, 매쓰랭 서비스의 백엔드 전반 개발중인 주니어 개발자입니다.

이번 포스팅에서, 네이버 oAuth Token Revocation 과정중에 생겼던 문제와 해결과정에 대해 얘기해보도록 하겠습니다.

문제

매쓰랭 서비스 회원가입은, 모두 oAuth를 통해 이뤄짐으로, 회원탈퇴 시 oAuth와의 연결해제는 반드시 필요한 과정입니다.

네이버는 Token Revocation에 아래의 세가지 API를 활용하도록 권고하고 있습니다.

    1. 서버에서 보관중인 refresh token를 통한 access token 재발급 API
    1. access token 유효성 검증 API
    1. access token 을 통한 토큰 폐기 API

위 API들로 서비스를 구현하는 과정에서, 회원탈퇴시 매쓰랭 서버에선 사용자 계정이 삭제되지만, 실제 네이버와의 oAuth 연결은 끊어지지 않는 문제가 발생했습니다.

문제해결 과정

앞서 살펴봤던데로 계정이 매쓰랭 서버에서만 삭제, Naver에선 삭제되지 않는것으로 미루어보아, 가장 먼저 확인해볼것은 Token Revocation API의 동작 확인이였습니다.

1. 문제분석

Token Revocation API는 호출 시, 폐기 결과와 함께 폐기한 토큰의 정보를 응답합니다.

Postman으로 해당 API를 검증한 결과, 전달된 access token의 유효성과는 별개로, 삭제에 성공했다면 항상 success를 응답하는것을 확인했습니다. 즉, 입력받은 access token이 실제로 존재하든 존재하지 않든, 항상 success를 리턴합니다.

  • 항상 success 응답함
  • access token의 유효성 확인 안함
  • 삭제한 토큰을 함께 응답함
 // 원본 access_token: 1

{
    "result": "success",
    "access_token": "1" // 입력된 토큰 그대로 옴!!
}

재밌는 점은, access_token에 + 문자가 포함되어있는 경우였습니다.

access_token+ 문자가 포함된 경우, +는 서버내에서 다음과 같이 공백으로 치환되었습니다.

 // 원본 access_token: aaa+++aaa

{
    "result": "success",
    "access_token": "aaa   aaa"
}

즉, 문제는 URL 인코딩이였습니다.

2. 문제 해결

공식문서 확인결과, 스프링의 URL 인코딩은, 크게 두가지 방식으로 이루어짐을 알 수 있었습니다.

UriComponentsBuilder exposes encoding options at two levels:

  • UriComponentsBuilder#encode(): Pre-encodes the URI template first and then strictly encodes URI variables when expanded.
  • UriComponents#encode(): Encodes URI components after URI variables are expanded.
    Both options replace non-ASCII and illegal characters with escaped octets. However, the first option also replaces characters with reserved meaning that appear in URI variables.

Consider ";", which is legal in a path but has reserved meaning. The first option replaces ";" with "%3B" in URI variables but not in the URI template. By contrast, the second option never replaces ";", since it is a legal character in a path.
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-uri-building.html

아래와 같이 템플릿 변수로 변경하니 + 까지 정상적으로 인코딩 되었고, 네이버 Token Revocation에서 내 access token을 정상적으로 폐기한걸 확인할 수 있었습니다.

		tokenClient.post()
			.uri(uriBuilder -> uriBuilder
				...
				.queryParam("access_token", "{access_token}") // 여기에 URI 템플릿 변수로 전달하기
				...
				.build(token.access_token())) // 전달!!
			.contentType(MediaType.APPLICATION_FORM_URLENCODED)
			.retrieve()
            ...

위와 같이 코드를 작성할 경우, DefaultUriBuilderFactory는, URI Template 변수를 인식해 Strict Encoding을 수행하게 됨으로 +문자가 정상적으로 인코딩 되는것을 확인할 수 있습니다.

가지가지...

1. Token Revocation API의 설명 부재

네이버 로그인 API 하단의 Token Revocation에 인코딩하란 설명이 없었다 ㅠㅠ

2. Token Revocation API의 항상 SUCCESS

네이버 Token Revocation API는 access_token의 유효여부와 상관없이 항상 SUCCESS를 응답했습니다.
이로 인해, 문제점을 파악하는데 난항을 겪었습니다. ㅠ

+) 하지만, 응답과 함께 오는 폐기된 access_token을 success와 함께 검증했으면, 문제를 파악할 수 있었을 것 같습니다.

3. RestClient의 느슨한 인코딩

RestClient의 인코딩 방식에 대해서 알게 됐습니다. 느슨한 인코딩이 적용된단 점과, 엄격한 인코딩을 위해선 url template을 통한 확장을 적용해야 한단 점을 알았습니다.

깨달은 점

결과적으로, RestClient의 URL 템플릿 변수를 사용할 때, strict encoding이 적용되어, 이전과 같이 + 문자가%2B로 인코딩 됨으로 서버에서 정상적으로 받는것을 확인할 수 있었습니다.

또한 유니코드, 퍼센트 인코딩, UTF-8과 같은 개념들에 대해 다시한번 돌아보게 되는 좋은 기회가 됐습니다. ㅎㅎ

profile
이건 나는 게 아냐, 멋지게 추락하는거지

0개의 댓글