구글 OAuth2를 위해 Feign Client 사용하던 중 발생했던 문제

 

액세스 토큰을 얻으려면 5단계: 승인 코드를 갱신 토큰 및 액세스 토큰으로 교환 에 나온대로

Content-Type: application/x-www-form-urlencoded 그리고 필드는 다음과 같이 작성해서 보내야한다.

client_id 클라이언트 ID
client_secret 클라이언트 secret key
code 초기 요청에서 반환된 승인 코드입니다.
grant_type OAuth 2.0 사양에 정의된 대로 이 필드의 값은 authorization_code로 설정해야 합니다.
redirect_uri 지정된 client_id의 에 프로젝트에 대해 나열된 리디렉션 URI 중 하나입니다.

 

그래서 필드는 확정적이니까 request dto를 평소처럼 record로 작성했다.

액세스 토큰을 얻기 위한 Feign Client 인터페이스는와 dto는 다음과 같다.

@FeignClient(name = "googleAuthClient", url = "https://oauth2.googleapis.com", configuration = OAuth2FeignConfig.class)
public interface GoogleOAuthClient {

    @PostMapping(value = "/token", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    GoogleOAuthResponse getToken(@RequestBody GoogleOAuthRequest request);
}
@Builder
public record GoogleOAuthRequest(
    String code,
    @FormProperty("client_id")
    String clientId,
    @FormProperty("client_secret")
    String clientSecret,
    @FormProperty("redirect_uri")
    String redirectUri,
    @FormProperty("grant_type")
    String grantType
) {
}

 

이렇게 작성하고 API를 찔러보니 4xx에러가 날라왔다. 원인을 찾다가 body에 들어가는 내용을 확인했더니, @FormProperty에 적힌대로 수정되어 request body에 들어가는게 아닌, 필드명 그대로 들어가는 것을 확인했다. (예를 들면, client_id가 아닌 clientId로 들어간다.)

 

왜지..? 그래서 FormProperty 오류를 찾아보다 해당 글을 발견했다. FeignClient @FormProperty 트러블 슈팅

링크를 건 포스트를 요약하면, @FormProperty로 설정된 이름으로 매핑되려면 해당 필드는 final 혹은 static이면 안된다는 것이다. 그런데 record를 사용하면 각 필드는 private final로 바뀌게 됨으로써 @FormProperty가 무시되는 것.

 

그래서 안타깝지만 dto를 일반 class로 변경했다.

@Builder
public class GoogleOAuthRequest {
    private String code;
    @FormProperty("client_id")
    private String clientId;
    @FormProperty("client_secret")
    private String clientSecret;
    @FormProperty("redirect_uri")
    private String redirectUri;
    @FormProperty("grant_type")
    private String grantType;
}

 

이후 요청을 보냈더니, 정상적인 응답을 받을 수 있었다.