diff --git a/Application-Module/src/main/kotlin/com/asap/application/user/port/in/SocialLoginUsecase.kt b/Application-Module/src/main/kotlin/com/asap/application/user/port/in/SocialLoginUsecase.kt index f0748da..ea3de7e 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/user/port/in/SocialLoginUsecase.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/user/port/in/SocialLoginUsecase.kt @@ -1,7 +1,6 @@ package com.asap.application.user.port.`in` interface SocialLoginUsecase { - fun login(command: Command): Response data class Command( @@ -9,16 +8,15 @@ interface SocialLoginUsecase { val accessToken: String, ) - sealed class Response { - } + sealed class Response data class Success( val accessToken: String, val refreshToken: String, - val isProcessedOnboarding: Boolean + val isProcessedOnboarding: Boolean, ) : Response() data class NonRegistered( - val registerToken: String + val registerToken: String, ) : Response() -} \ No newline at end of file +} diff --git a/Application-Module/src/main/kotlin/com/asap/application/user/port/out/AuthInfoRetrievePort.kt b/Application-Module/src/main/kotlin/com/asap/application/user/port/out/AuthInfoRetrievePort.kt index 9825553..99238be 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/user/port/out/AuthInfoRetrievePort.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/user/port/out/AuthInfoRetrievePort.kt @@ -5,7 +5,15 @@ import com.asap.application.user.vo.AuthInfo import com.asap.domain.user.enums.SocialLoginProvider interface AuthInfoRetrievePort { - @Throws(UserException.UserAuthNotFoundException::class) - fun getAuthInfo(provider: SocialLoginProvider, accessToken: String): AuthInfo -} \ No newline at end of file + fun getAuthInfo( + provider: SocialLoginProvider, + accessToken: String, + ): AuthInfo + + fun getAccessToken( + provider: SocialLoginProvider, + code: String, + state: String, + ): String +} diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/api/AuthApi.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/api/AuthApi.kt index cd12672..fc7c274 100644 --- a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/api/AuthApi.kt +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/api/AuthApi.kt @@ -1,10 +1,7 @@ package com.asap.bootstrap.web.auth.api import com.asap.bootstrap.common.exception.ExceptionResponse -import com.asap.bootstrap.web.auth.dto.ReissueRequest -import com.asap.bootstrap.web.auth.dto.ReissueResponse -import com.asap.bootstrap.web.auth.dto.SocialLoginRequest -import com.asap.bootstrap.web.auth.dto.SocialLoginResponse +import com.asap.bootstrap.web.auth.dto.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema @@ -62,6 +59,38 @@ interface AuthApi { @RequestBody request: SocialLoginRequest, ): ResponseEntity + @Operation(summary = "OAuth 액세스 토큰 획득") + @PostMapping("/token/{provider}") + @ApiResponses( + value = [ + ApiResponse( + responseCode = "200", + description = "액세스 토큰 획득 성공", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = OAuthAccessTokenResponse::class), + ), + ], + ), + ApiResponse( + responseCode = "4XX", + description = "액세스 토큰 획득 실패", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ExceptionResponse::class), + ), + ], + ), + ], + ) + fun getAccessToken( + @Schema(description = "소셜 로그인 플랫폼, ex) KAKAO, GOOGLE, NAVER") + @PathVariable provider: String, + @RequestBody request: OAuthAccessTokenRequest, + ): OAuthAccessTokenResponse + @Operation(summary = "토큰 재발급") @PostMapping("/reissue") @ApiResponses( diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/controller/AuthController.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/controller/AuthController.kt index 408411e..bcd737e 100644 --- a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/controller/AuthController.kt +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/controller/AuthController.kt @@ -2,11 +2,10 @@ package com.asap.bootstrap.web.auth.controller import com.asap.application.user.port.`in`.ReissueTokenUsecase import com.asap.application.user.port.`in`.SocialLoginUsecase +import com.asap.application.user.port.out.AuthInfoRetrievePort import com.asap.bootstrap.web.auth.api.AuthApi -import com.asap.bootstrap.web.auth.dto.ReissueRequest -import com.asap.bootstrap.web.auth.dto.ReissueResponse -import com.asap.bootstrap.web.auth.dto.SocialLoginRequest -import com.asap.bootstrap.web.auth.dto.SocialLoginResponse +import com.asap.bootstrap.web.auth.dto.* +import com.asap.domain.user.enums.SocialLoginProvider import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RestController @@ -15,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController class AuthController( private val socialLoginUsecase: SocialLoginUsecase, private val reissueTokenUsecase: ReissueTokenUsecase, + private val authInfoRetrievePort: AuthInfoRetrievePort, ) : AuthApi { override fun socialLogin( provider: String, @@ -54,4 +54,19 @@ class AuthController( refreshToken = response.refreshToken, ) } + + override fun getAccessToken( + provider: String, + request: OAuthAccessTokenRequest, + ): OAuthAccessTokenResponse { + val accessToken = + authInfoRetrievePort.getAccessToken( + provider = SocialLoginProvider.valueOf(provider), + code = request.code, + state = request.state, + ) + return OAuthAccessTokenResponse( + accessToken = accessToken, + ) + } } diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/dto/OAuthAccessTokenRequest.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/dto/OAuthAccessTokenRequest.kt new file mode 100644 index 0000000..dddf04a --- /dev/null +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/dto/OAuthAccessTokenRequest.kt @@ -0,0 +1,6 @@ +package com.asap.bootstrap.web.auth.dto + +data class OAuthAccessTokenRequest( + val code: String, + val state: String, +) diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/dto/OAuthAccessTokenResponse.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/dto/OAuthAccessTokenResponse.kt new file mode 100644 index 0000000..c0682ec --- /dev/null +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/dto/OAuthAccessTokenResponse.kt @@ -0,0 +1,5 @@ +package com.asap.bootstrap.web.auth.dto + +data class OAuthAccessTokenResponse( + val accessToken: String, +) diff --git a/Bootstrap-Module/src/main/resources/application.yml b/Bootstrap-Module/src/main/resources/application.yml index 15e69ef..5321b4e 100644 --- a/Bootstrap-Module/src/main/resources/application.yml +++ b/Bootstrap-Module/src/main/resources/application.yml @@ -5,14 +5,17 @@ spring: - security - aws - persistence + - client local: - security-local - aws-local - persistence-local + - client-local test: - security-local - aws-local - persistence-test + - client-local active: local diff --git a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/auth/controller/AuthControllerTest.kt b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/auth/controller/AuthControllerTest.kt index e2054f4..175e162 100644 --- a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/auth/controller/AuthControllerTest.kt +++ b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/auth/controller/AuthControllerTest.kt @@ -4,9 +4,12 @@ import com.asap.application.user.port.`in`.LogoutUsecase import com.asap.application.user.port.`in`.ReissueTokenUsecase import com.asap.application.user.port.`in`.SocialLoginUsecase import com.asap.application.user.port.`in`.TokenResolveUsecase +import com.asap.application.user.port.out.AuthInfoRetrievePort import com.asap.bootstrap.AcceptanceSupporter +import com.asap.bootstrap.web.auth.dto.OAuthAccessTokenRequest import com.asap.bootstrap.web.auth.dto.ReissueRequest import com.asap.bootstrap.web.auth.dto.SocialLoginRequest +import com.asap.domain.user.enums.SocialLoginProvider import org.junit.jupiter.api.Test import org.mockito.BDDMockito import org.springframework.boot.test.mock.mockito.MockBean @@ -26,6 +29,9 @@ class AuthControllerTest : AcceptanceSupporter() { @MockBean private lateinit var logoutUsecase: LogoutUsecase + @MockBean + private lateinit var authInfoRetrievePort: AuthInfoRetrievePort + @Test fun socialLoginSuccessTest() { // given @@ -112,4 +118,35 @@ class AuthControllerTest : AcceptanceSupporter() { } } } + + @Test + fun getAccessTokenTest() { + // given + val provider = "KAKAO" + val code = "authorization_code" + val state = "state" + val request = OAuthAccessTokenRequest(code, state) + val expectedAccessToken = "access_token" + + BDDMockito + .given(authInfoRetrievePort.getAccessToken(SocialLoginProvider.valueOf(provider), code, state)) + .willReturn(expectedAccessToken) + + // when + val response = + mockMvc.post("/api/v1/auth/token/{provider}", provider) { + contentType = MediaType.APPLICATION_JSON + content = objectMapper.writeValueAsString(request) + } + + // then + response.andExpect { + status { isOk() } + jsonPath("$.accessToken") { + exists() + isString() + value(expectedAccessToken) + } + } + } } diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientConfig.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientConfig.kt index 22f4995..2495455 100644 --- a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientConfig.kt +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientConfig.kt @@ -1,9 +1,10 @@ package com.asap.client +import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration @Configuration @ComponentScan(basePackages = ["com.asap.client"]) -class ClientConfig { -} \ No newline at end of file +@EnableConfigurationProperties(ClientProperties::class) +class ClientConfig diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientProperties.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientProperties.kt new file mode 100644 index 0000000..782535a --- /dev/null +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/ClientProperties.kt @@ -0,0 +1,17 @@ +package com.asap.client + +import org.springframework.boot.context.properties.ConfigurationProperties + +@ConfigurationProperties(prefix = "client") +class ClientProperties( + var oauth: OAuthProperties = OAuthProperties(), +) + +class OAuthProperties( + var naver: NaverOAuthProperties = NaverOAuthProperties(), +) + +class NaverOAuthProperties( + var clientId: String = "", + var clientSecret: String = "", +) diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthInfoRetrieveAdapter.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthInfoRetrieveAdapter.kt index 762003c..af01e08 100644 --- a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthInfoRetrieveAdapter.kt +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthInfoRetrieveAdapter.kt @@ -30,4 +30,16 @@ class OAuthInfoRetrieveAdapter( throw UserException.UserAuthNotFoundException("OAuth 정보를 가져오는데 실패했습니다. 에러 메시지: ${e.message}") } } + + override fun getAccessToken( + provider: SocialLoginProvider, + code: String, + state: String, + ): String { + val accessTokenResponse = + oAuthRetrieveHandlers[provider]?.getAccessToken(OAuthRetrieveHandler.OAuthGetAccessTokenRequest(code, state)) + ?: throw OAuthException.OAuthRetrieveFailedException("OAuth Access Token을 가져오는 핸들러가 존재하지 않습니다.") + + return accessTokenResponse.accessToken + } } diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthRetrieveHandler.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthRetrieveHandler.kt index fb197b6..6a2fe55 100644 --- a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthRetrieveHandler.kt +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthRetrieveHandler.kt @@ -3,6 +3,9 @@ package com.asap.client.oauth interface OAuthRetrieveHandler { fun getOAuthInfo(request: OAuthRequest): OAuthResponse + fun getAccessToken(request: OAuthGetAccessTokenRequest): OAuthAccessTokenResponse = + throw UnsupportedOperationException("This operation is not supported yet.") + data class OAuthRequest( val accessToken: String, ) @@ -13,4 +16,14 @@ interface OAuthRetrieveHandler { val email: String, val profileImage: String, ) + + data class OAuthGetAccessTokenRequest( + val code: String, + val state: String, + ) + + data class OAuthAccessTokenResponse( + val accessToken: String, + val refreshToken: String?, + ) } diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthWebClientConfig.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthWebClientConfig.kt index 980cfd3..3400f3f 100644 --- a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthWebClientConfig.kt +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/OAuthWebClientConfig.kt @@ -34,4 +34,13 @@ class OAuthWebClientConfig { .baseUrl("https://openapi.naver.com") .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) .build() + + @Bean + @Qualifier("getNaverAccessTokenWebClient") + fun getNaverAccessTokenWebClient(): WebClient = + WebClient + .builder() + .baseUrl("https://nid.naver.com") + .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .build() } diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/AbstractOAuthRetrieveHandler.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/AbstractOAuthRetrieveHandler.kt index 9091768..955ccbd 100644 --- a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/AbstractOAuthRetrieveHandler.kt +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/AbstractOAuthRetrieveHandler.kt @@ -5,20 +5,20 @@ import com.asap.client.oauth.exception.OAuthException import org.springframework.web.reactive.function.client.WebClient abstract class AbstractOAuthRetrieveHandler( - private val webClient: WebClient, + protected val webClient: WebClient, ) : OAuthRetrieveHandler { - override fun getOAuthInfo(request: OAuthRetrieveHandler.OAuthRequest): OAuthRetrieveHandler.OAuthResponse { - val response = webClient - .get() - .uri(getApiEndpoint()) - .header("Authorization", "Bearer ${request.accessToken}") - .retrieve() - .onStatus({ it.isError }, { - throw OAuthException.OAuthRetrieveFailedException(getErrorMessage()) - }) - .bodyToMono(getResponseType()) - .block() + val response = + webClient + .get() + .uri(getApiEndpoint()) + .header("Authorization", "Bearer ${request.accessToken}") + .retrieve() + .onStatus({ it.isError }, { + throw OAuthException.OAuthRetrieveFailedException(getErrorMessage()) + }) + .bodyToMono(getResponseType()) + .block() if (response == null) { throw OAuthException.OAuthRetrieveFailedException(getErrorMessage()) @@ -46,4 +46,4 @@ abstract class AbstractOAuthRetrieveHandler( * Maps the provider-specific response to a common OAuthResponse */ protected abstract fun mapToOAuthResponse(response: T): OAuthRetrieveHandler.OAuthResponse -} \ No newline at end of file +} diff --git a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandler.kt b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandler.kt index 1724e78..07426bb 100644 --- a/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandler.kt +++ b/Infrastructure-Module/Client/src/main/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandler.kt @@ -1,31 +1,61 @@ package com.asap.client.oauth.platform +import com.asap.client.ClientProperties import com.asap.client.oauth.OAuthRetrieveHandler +import com.asap.client.oauth.exception.OAuthException +import com.fasterxml.jackson.annotation.JsonProperty import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.util.UriComponentsBuilder @Component class NaverOAuthRetrieveHandler( @Qualifier("naverWebClient") naverWebClient: WebClient, -) : AbstractOAuthRetrieveHandler(naverWebClient) { + @Qualifier("getNaverAccessTokenWebClient") val getNaverAccessTokenWebClient: WebClient, + private val clientProperties: ClientProperties, +) : AbstractOAuthRetrieveHandler(naverWebClient) { + private val naverOAuthConfig by lazy { clientProperties.oauth.naver } + + override fun getAccessToken(request: OAuthRetrieveHandler.OAuthGetAccessTokenRequest): OAuthRetrieveHandler.OAuthAccessTokenResponse { + val accessTokenUrl = + NaverAccessTokenRequest( + grantType = "authorization_code", + clientId = naverOAuthConfig.clientId, + clientSecret = naverOAuthConfig.clientSecret, + code = request.code, + ).toUriComponents("/oauth2.0/token") + + val response = + getNaverAccessTokenWebClient + .get() + .uri(accessTokenUrl) + .retrieve() + .bodyToMono(NaverAccessTokenResponse::class.java) + .block() + ?: throw OAuthException.OAuthRetrieveFailedException(getErrorMessage()) + + return OAuthRetrieveHandler.OAuthAccessTokenResponse( + accessToken = response.accessToken, + refreshToken = response.tokenType, + ) + } override fun getApiEndpoint(): String = "/v1/nid/me" override fun getErrorMessage(): String = "네이버 사용자 정보를 가져오는데 실패했습니다." - override fun getResponseType(): Class = NaverApiResponse::class.java + override fun getResponseType(): Class = NaverOAuthUserInfoResponse::class.java - override fun mapToOAuthResponse(response: NaverApiResponse): OAuthRetrieveHandler.OAuthResponse { - return OAuthRetrieveHandler.OAuthResponse( - username = response.response.nickname, + override fun mapToOAuthResponse(response: NaverOAuthUserInfoResponse): OAuthRetrieveHandler.OAuthResponse = + OAuthRetrieveHandler.OAuthResponse( + username = "", socialId = response.response.id, email = response.response.email, - profileImage = response.response.profile_image, + profileImage = "", ) - } - data class NaverApiResponse( + data class NaverOAuthUserInfoResponse( val resultcode: String, val message: String, val response: NaverUserResponse, @@ -33,14 +63,33 @@ class NaverOAuthRetrieveHandler( data class NaverUserResponse( val id: String, - val nickname: String, - val name: String, val email: String, - val gender: String, - val age: String, - val birthday: String, - val profile_image: String, - val birthyear: String, - val mobile: String, + ) + + data class NaverAccessTokenRequest( + val grantType: String, + val clientId: String, + val clientSecret: String, + val code: String, + ) { + fun toUriComponents(basePath: String): String = + UriComponentsBuilder + .fromPath(basePath) + .queryParam("grant_type", grantType) + .queryParam("client_id", clientId) + .queryParam("client_secret", clientSecret) + .queryParam("code", code) + .toUriString() + } + + data class NaverAccessTokenResponse( + @JsonProperty("access_token") + val accessToken: String, + @JsonProperty("refresh_token") + val refreshToken: String, + @JsonProperty("token_type") + val tokenType: String, + @JsonProperty("expires_in") + val expiresIn: Int, ) } diff --git a/Infrastructure-Module/Client/src/main/resources/application-client-local.yml b/Infrastructure-Module/Client/src/main/resources/application-client-local.yml new file mode 100644 index 0000000..4be1bd9 --- /dev/null +++ b/Infrastructure-Module/Client/src/main/resources/application-client-local.yml @@ -0,0 +1,5 @@ +client: + oauth: + naver: + client_id: not-config-client-id + client_secret: not-config-client-secret \ No newline at end of file diff --git a/Infrastructure-Module/Client/src/main/resources/application-client.yml b/Infrastructure-Module/Client/src/main/resources/application-client.yml new file mode 100644 index 0000000..5468572 --- /dev/null +++ b/Infrastructure-Module/Client/src/main/resources/application-client.yml @@ -0,0 +1,5 @@ +client: + oauth: + naver: + client_id: ${NAVER_OAUTH_CLIENT_ID} + client_secret: ${NAVER_OAUTH_CLIENT_SECRET} \ No newline at end of file diff --git a/Infrastructure-Module/Client/src/test/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandlerTest.kt b/Infrastructure-Module/Client/src/test/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandlerTest.kt index 2995104..da7ad97 100644 --- a/Infrastructure-Module/Client/src/test/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandlerTest.kt +++ b/Infrastructure-Module/Client/src/test/kotlin/com/asap/client/oauth/platform/NaverOAuthRetrieveHandlerTest.kt @@ -1,5 +1,8 @@ package com.asap.client.oauth.platform +import com.asap.client.ClientProperties +import com.asap.client.NaverOAuthProperties +import com.asap.client.OAuthProperties import com.asap.client.oauth.OAuthRetrieveHandler import com.asap.client.oauth.exception.OAuthException import io.kotest.assertions.throwables.shouldThrow @@ -12,16 +15,29 @@ import org.springframework.web.reactive.function.client.WebClient class NaverOAuthRetrieveHandlerTest : BehaviorSpec({ - var mockWebServer = MockWebServer().also { - it.start() - } + var mockWebServer = + MockWebServer().also { + it.start() + } var naverWebClient: WebClient = WebClient .builder() .baseUrl(mockWebServer.url("/").toString()) .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) .build() - var naverOAuthRetrieveHandler = NaverOAuthRetrieveHandler(naverWebClient) + + val config = + ClientProperties( + oauth = + OAuthProperties( + naver = + NaverOAuthProperties( + clientId = "test-client-id", + clientSecret = "test-client-secret", + ), + ), + ) + var naverOAuthRetrieveHandler = NaverOAuthRetrieveHandler(naverWebClient, naverWebClient, config) given("OAuth 요청이 성공적으로 처리되었을 때") { val accessToken = "test-access-token" @@ -58,10 +74,8 @@ class NaverOAuthRetrieveHandlerTest : val response = naverOAuthRetrieveHandler.getOAuthInfo(request) then("올바른 OAuthResponse를 반환해야 한다") { - response.username shouldBe "Test User" response.socialId shouldBe "12345" response.email shouldBe "test@example.com" - response.profileImage shouldBe "https://example.com/profile.jpg" // 요청 검증 val recordedRequest = mockWebServer.takeRequest() @@ -110,4 +124,4 @@ class NaverOAuthRetrieveHandlerTest : } } } - }) \ No newline at end of file + })