8Avengers / YumYum-BE

2 stars 1 forks source link

[Feature] : Passport 쓰지 않는 Oauth 기능 구현 #165

Closed favorsyoon closed 1 year ago

favorsyoon commented 1 year ago

백엔드는 응답만, 프론트는 요청만

favorsyoon commented 1 year ago

공부해보자. 참고해야할 것

https://github.com/mwanago/nestjs-typescript/tree/master/src/googleAuthentication

https://wanago.io/2021/07/26/api-nestjs-google-authentication/

https://velog.io/@nuri00/Google-OAuth-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84

favorsyoon commented 1 year ago

마지막으로 해결할 수 있었던 이유 :

아래는 프론트(리액트)에서 구글로 요청하는 주소다.

https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=${googleClientId}&scope=openid%20profile%20email&redirect_uri=${googleRedirectUrl}

response_type=code or response_type=access_token

그동안 response_type=access_token 대부분 블로거들이 프론트에서 액세스토큰을 받았나보다.
그래서 계속 아래와 같은 에러메시지를 백엔드 서버에서 받았다.

Error response from Google API: { error: 'invalid_grant', error_description: 'Malformed auth code.' }
[2023-03-23T08:04:03.692Z] error: AxiosError: Request failed with status code 400
[Nest] 17916  - 2023. 03. 23. 오후 5:04:03   ERROR [ExceptionsHandler] Request failed with status code 400
Error: Request failed with status code 400
    at GoogleOauthService.getOAuthTokensFromGoogle (C:\Users\enter\OneDrive\바탕 화면\YumYum_Avengers\src\apis\auth\google-oauth.service.ts:65:13)  
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at C:\Users\enter\OneDrive\바탕 화면\YumYum_Avengers\node_modules\@nestjs\core\router\router-execution-context.js:46:28
    at C:\Users\enter\OneDrive\바탕 화면\YumYum_Avengers\node_modules\@nestjs\core\router\router-proxy.js:9:17

Oauth 로직을 정리해보면,

  1. 프론트에서 개발자도구에서 얻을 수 있는 secretid, key, redirectUrl 이 3가지를 조합해서 URL로 만들어서 구글에 요청을 한다.

  2. 구글에 요청하면, 구글에서 code를 준다.

code를 받아서 이 code를 백엔드에 넘겨서 백엔드에 받아온 code+ client_id + client_secret + redirect_uri + grant_type 이 5가지를 모두 총합해서

백엔드서버에서 구글에 유저정보를 달라고 post 요청을 보낸다.

요청한 4가지 정보가 유효하다면, 구글에서 우리서버에게 사용자정보(email,name.nickname)과 같은 정보를 넘겨주는데, 이것을 DB에 저장하고 회원가입 => 로그인을 하나의 authservice.ts에서 진행시키고 난 다음

accessToken 과 refreshToken을 우리 백엔드 서버에서 JWT token으로 발급해서 프론트에 response body로 응답해주면 된다.

근데,

내가 계속해서 실패했던 이유는 아래와 같은 에러메시지를 백엔드 서버에서 받은 이유는

Error response from Google API: { error: 'invalid_grant', error_description: 'Malformed auth code.' }
[2023-03-23T08:04:03.692Z] error: AxiosError: Request failed with status code 400
[Nest] 17916  - 2023. 03. 23. 오후 5:04:03   ERROR [ExceptionsHandler] Request failed with status code 400
Error: Request failed with status code 400
    at GoogleOauthService.getOAuthTokensFromGoogle (C:\Users\enter\OneDrive\바탕 화면\YumYum_Avengers\src\apis\auth\google-oauth.service.ts:65:13)  
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at C:\Users\enter\OneDrive\바탕 화면\YumYum_Avengers\node_modules\@nestjs\core\router\router-execution-context.js:46:28
    at C:\Users\enter\OneDrive\바탕 화면\YumYum_Avengers\node_modules\@nestjs\core\router\router-proxy.js:9:17

내가 참고했던 대부분의 블로그들이 프론트에서 요청하는 URL에서 response_type을 accesstoken 을 쓰거나 편리한 라이브러리를 써버린다. 그래서 code로 받는 요청주소가 없었다. 사실 많이 의아하기는 했다. kakao, naver 모두 code로 받았지만, google만 계속해서 URL에 response_type=access_token으로 받았기 때문이다. 그냥 구글이 뭔가 특별한가? 외국사이트라 그런가? 생각하면서 넘어갔었다.

근데 밸로그에 글 쓴 한분을 찾아서, code를 구글에 받아서 이 코드를 백엔드에 request body로 보내줄 수 있었다.

//auth.controller.ts

  //소셜로그인 - passport 미사용 (구글 + 네이버 + 카카오)
  @Post('oauth/login/:provider')
  @HttpCode(200)
  async oauthSignIn(
    @Param('provider') provider: string,
    @Body() body: SocialLoginBodyDTO,
  ) {
    console.log('Check if its coming in', provider, body);

    if (provider === 'google') {
      return await this.authService.oauthLoginGoogle(provider, body);
    } else if (provider === 'kakao') {
      return await this.authService.oauthLoginSocial(provider, body);
    } else if (provider === 'naver') {
      return await this.authService.oauthLoginSocial(provider, body);
    } else {
      throw new BadRequestException(`Invalid provider: ${provider}`);
    }
  }

참고한 블로그 주소: https://velog.io/@leejpsd/React-%EC%86%8C%EC%85%9C%EB%A1%9C%EA%B7%B8%EC%9D%B8-OAuth