SpringBoot

[SpringBoot] 3.x OAuth2 invalid_token_response 문제

진세박 2023. 1. 13. 12:48

SpringBoot 3.0.1 로 업데이트 후 OAuth2 로 소셜 로그인을 진행하는데

계속 token을 받아올 수 없는 현상이 발생했다.

 

[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized: [no body]

 

분명 client-authentication-method: post 를 잘 적어주었고

client-id, client-secret 까지 틀림없이 적었는데 오류가 계속 났다..

구글을 다 찾아보고 공식 문서를 뒤져봤지만 도무지 찾을 수 없었다.

 

하지만 카카오 api 에서 secret 기능을 끄면 소셜 로그인이 잘 됐다.

secret 코드 쪽이 문제구나 싶어서 이쪽을 중점으로 디버깅 해보았다.

 

3일 삽질 후 찾아낸 결과이다.

아래의 클래스가 문제였다.

public class OAuth2AuthorizationCodeGrantRequestEntityConverter
		extends AbstractOAuth2AuthorizationGrantRequestEntityConverter<OAuth2AuthorizationCodeGrantRequest> {

	@Override
	protected MultiValueMap<String, String> createParameters(
			OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
		ClientRegistration clientRegistration = authorizationCodeGrantRequest.getClientRegistration();
		OAuth2AuthorizationExchange authorizationExchange = authorizationCodeGrantRequest.getAuthorizationExchange();
		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
		parameters.add(OAuth2ParameterNames.GRANT_TYPE, authorizationCodeGrantRequest.getGrantType().getValue());
		parameters.add(OAuth2ParameterNames.CODE, authorizationExchange.getAuthorizationResponse().getCode());
		String redirectUri = authorizationExchange.getAuthorizationRequest().getRedirectUri();
		String codeVerifier = authorizationExchange.getAuthorizationRequest()
				.getAttribute(PkceParameterNames.CODE_VERIFIER);
		if (redirectUri != null) {
			parameters.add(OAuth2ParameterNames.REDIRECT_URI, redirectUri);
		}
		if (!ClientAuthenticationMethod.CLIENT_SECRET_BASIC.equals(clientRegistration.getClientAuthenticationMethod())
				&& !ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
			parameters.add(OAuth2ParameterNames.CLIENT_ID, clientRegistration.getClientId());
		}
		if (ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientRegistration.getClientAuthenticationMethod())
				|| ClientAuthenticationMethod.POST.equals(clientRegistration.getClientAuthenticationMethod())) {
			parameters.add(OAuth2ParameterNames.CLIENT_SECRET, clientRegistration.getClientSecret());
		}
		if (codeVerifier != null) {
			parameters.add(PkceParameterNames.CODE_VERIFIER, codeVerifier);
		}
		return parameters;
	}

}

SpringBoot 2.x 버전의 security-oauth2-client 코드중

OAuth2AuthorizationCodeGrantRequestEntityConverter 클래스의 코드이다.

 

if (ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientRegistration.getClientAuthenticationMethod())
        || ClientAuthenticationMethod.POST.equals(clientRegistration.getClientAuthenticationMethod())) {
    parameters.add(OAuth2ParameterNames.CLIENT_SECRET, clientRegistration.getClientSecret());
}

이 부분을 보면 oauth2 관련 properties나 yml을 작성할 때 

 

client-authentication-method: post

OR

client-authentication-method: client_secret_post

 

를 작성해주면 if문이 true가 돼서 파라미터가 추가가 됐었다.

 

하지만...

public class OAuth2AuthorizationCodeGrantRequestEntityConverter
		extends AbstractOAuth2AuthorizationGrantRequestEntityConverter<OAuth2AuthorizationCodeGrantRequest> {

	@Override
	protected MultiValueMap<String, String> createParameters(
			OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
		ClientRegistration clientRegistration = authorizationCodeGrantRequest.getClientRegistration();
		OAuth2AuthorizationExchange authorizationExchange = authorizationCodeGrantRequest.getAuthorizationExchange();
		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
		parameters.add(OAuth2ParameterNames.GRANT_TYPE, authorizationCodeGrantRequest.getGrantType().getValue());
		parameters.add(OAuth2ParameterNames.CODE, authorizationExchange.getAuthorizationResponse().getCode());
		String redirectUri = authorizationExchange.getAuthorizationRequest().getRedirectUri();
		String codeVerifier = authorizationExchange.getAuthorizationRequest()
				.getAttribute(PkceParameterNames.CODE_VERIFIER);
		if (redirectUri != null) {
			parameters.add(OAuth2ParameterNames.REDIRECT_URI, redirectUri);
		}
		if (!ClientAuthenticationMethod.CLIENT_SECRET_BASIC
				.equals(clientRegistration.getClientAuthenticationMethod())) {
			parameters.add(OAuth2ParameterNames.CLIENT_ID, clientRegistration.getClientId());
		}
		if (ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientRegistration.getClientAuthenticationMethod())) {
			parameters.add(OAuth2ParameterNames.CLIENT_SECRET, clientRegistration.getClientSecret());
		}
		if (codeVerifier != null) {
			parameters.add(PkceParameterNames.CODE_VERIFIER, codeVerifier);
		}
		return parameters;
	}

}

SpringBoot 3.x의 security-oauth2-client 코드이다.

다른 점이 보이는가

 

if (ClientAuthenticationMethod.CLIENT_SECRET_POST.equals(clientRegistration.getClientAuthenticationMethod())) {
    parameters.add(OAuth2ParameterNames.CLIENT_SECRET, clientRegistration.getClientSecret());
}

POST 가 사라졌다!!! 이런...

그래서 client-authentication-method: post 를 해도 요청 파라미터에 client-secret 값이 추가가 안되는 것 이었다..........

 

결론

client-authentication-method: client_secret_post 으로 해주면 해결할 수 있다. (대문자도 안됨)