로그인 토큰 발급 api 호출

현재 내 애플리케이션 플랫폼에 도메인은 http://localhost:3000 로 설정했고
Redirect URI 은 http://localhost:3000/v1/auth/login/kakao 로 설정한 상태입니다.

아래 api로 인가코드을 요청하고
https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=REST_API_KEY&redirect_uri=http://localhost:3000/v1/auth/login/kakao

{“statusCode”:404,“message”:“Cannot GET /v1/auth/login/kakao?code=85_FNEKucS6N23ooxDAFGqurVasceBtj4RXVKQhzO7r6I7pYT64NpNbTES7F05g1QnQ9Jgo9dBEAAAF8_qhTBQ”,“error”:“Not Found”}
이런 응답을 받았습니다.

이 후에 code 값 85_FNEKucS6N23ooxDAFGqurVasceBtj4RXVKQhzO7r6I7pYT64NpNbTES7F05g1QnQ9Jgo9dBEAAAF8_qhTBQ 를
아래 함수에 넣어 토큰을 요청하는데
도저히 되질 않네요…ㅠ 계속 401에러가 나고…

async getKakaoToken(code:string) {
        return await axios({
          method: 'POST',
          url: 'https://kauth.kakao.com/oauth/token',
          headers : { 
            'Content-type' : 'application/x-www-form-urlencoded;charset=utf-8'
          },
          data: {
            grant_type : "authorization_code",
            client_id :REST_API_KEY,
            redirect_uri : "http://localhost:3000/v1/auth/login/kakao",
            code : code
          }
        });
      }

위의 함수처럼 해보기도 하고
아래처럼 form 데이터로 한번 더 바꿔서 data를 전송하면

async getKakaoToken(code:string) {
    const makeFormData = params => {
      const searchParams = new URLSearchParams()
      Object.keys(params).forEach(key => {
        searchParams.append(key, params[key])
      })
  
      return searchParams
    }

    return await axios({
      method: 'POST',
      url: 'https://kauth.kakao.com/oauth/token',
      headers : { 
        'Content-type' : 'application/x-www-form-urlencoded;charset=utf-8'
      },
      data: makeFormData({
        grant_type : "authorization_code",
        client_id : REST_API_KEY,
        redirect_uri : "http://localhost:3000/v1/auth/login/kakao",
        code : code
      })
    });
  } 

[Nest] 10620 - 2021. 11. 08. 오후 4:56:52 ERROR [ExceptionsHandler] Converting circular structure to JSON
→ starting at object with constructor ‘ClientRequest’
| property ‘socket’ → object with constructor ‘TLSSocket’
— property ‘_httpMessage’ closes the circle
TypeError: Converting circular structure to JSON
→ starting at object with constructor ‘ClientRequest’
| property ‘socket’ → object with constructor ‘TLSSocket’
— property ‘_httpMessage’ closes the circle
at JSON.stringify ()
at stringify (C:\Users\dexign\Desktop\jebs-api\node_modules\express\lib\response.js:1123:12)
at ServerResponse.json (C:\Users\dexign\Desktop\jebs-api\node_modules\express\lib\response.js:260:14)
at ExpressAdapter.reply (C:\Users\dexign\Desktop\jebs-api\node_modules@nestjs\platform-express\adapters\express-adapter.js:32:57)
at RouterResponseController.apply (C:\Users\dexign\Desktop\jebs-api\node_modules@nestjs\core\router\router-response-controller.js:14:36)
at C:\Users\dexign\Desktop\jebs-api\node_modules@nestjs\core\router\router-execution-context.js:175:48
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at C:\Users\dexign\Desktop\jebs-api\node_modules@nestjs\core\router\router-execution-context.js:47:13
at C:\Users\dexign\Desktop\jebs-api\node_modules@nestjs\core\router\router-proxy.js:9:17

이런 에러가 납니다…
제 앱id는 661116 입니다

아래 에러는 소유하신 사이트에 해당 파일 혹은 api가 없다는 의미 같구요.
“statusCode”:404,“message”:“Cannot GET /v1/auth/login/kakao?

인가 code 값 으로 401은 이미 사용된 인가코드를 재사용하신 것 같습니다.

확인 부탁드립니다.


  async getKakaoToken(code:string) {
    return await axios({   
      method: 'POST',
      headers: {
        'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
      },
      url: 'https://kauth.kakao.com/oauth/token',
      data: {
        grant_type: 'authorization_code',
        client_id: "43c9642fc1542525ba497a549de4a6b8",
        redirect_uri: "http://localhost:3000/v1/auth/login/kakao",
        code
      }
    });
  }

위의 함수의 상태에서 새롭게 발급 받은 code를 써도 401이 나옵니다…

[Nest] 6308 - 2021. 11. 09. 오전 10:06:07 ERROR [ExceptionsHandler] Request failed with status code 401
Error: Request failed with status code 401
at createError (C:\Users\dexign\Desktop\jebs-api\node_modules\axios\lib\core\createError.js:16:15)
at settle (C:\Users\dexign\Desktop\jebs-api\node_modules\axios\lib\core\settle.js:17:12)
at IncomingMessage.handleStreamEnd (C:\Users\dexign\Desktop\jebs-api\node_modules\axios\lib\adapters\http.js:269:11)
at IncomingMessage.emit (events.js:412:35)
at IncomingMessage.emit (domain.js:470:12)
at endReadableNT (internal/streams/readable.js:1317:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21)

이렇게요 ㅠ

그리고 아래처럼 form 데이터로 인코딩 후에 data를 전달해도 같은 에러가 납니다

  async getKakaoToken(code:string) {    

    const makeFormData = params => {
      const data = new FormData();
      Object.keys(params).forEach(key => {
        data.append(key, params[key]);
      });
      return data
    }
    return await axios({   
      method: 'POST',
      headers: {
        'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
      },
      url: 'https://kauth.kakao.com/oauth/token',
      data: await makeFormData({
        grant_type: 'authorization_code',
        client_id: "43c9642fc1542525ba497a549de4a6b8",
        redirect_uri: "http://localhost:3000/v1/auth/login/kakao",
        code
      })
    });
  }

혹시 redirect_url이 토큰 요청 api의 url과 같아야 한다거나 달라야한다거나 등과 같은 조건이 있나요?
아니면 코드 자체(예. 85_FNEKucS6N23ooxDAFGqurVasceBtj4RXVKQhzO7r6I7pYT64NpNbTES7F05g1QnQ9Jgo9dBEAAAF8_qhTBQ)를 보내는 게 아니라, 이 코드 값을 수정한 후에 보내야 하나요??
도저히 안되는 이유를 모르겠습니다.

참고로 nest.js로 작업을 하고있고
인가코드는 아래 url을 직접 브라우저 주소창에 입력하여 발급받고 있습니다.

https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=43c9642fc1542525ba497a549de4a6b8&redirect_uri=http://localhost:3000/v1/auth/login/kakao`

새롭게 발급 받아 사용하였는데도 오류발생한 인가 code 기재해주시겠어요? 로그확인해보겠습니다.

redirect_url이 토큰 요청 api의 url과 같아야 한다거나 달라야한다거나 등과 같은 조건이 있나요?

그런 조건은 없고

인가요청과 토큰요청에 사용하는 redirect_url는 동일한 값을 사용해야하구요.

redirect_url에서 받은 인가 코드를 토큰요청시에 1회 사용하기만 하면됩니다.

198Jw7NxR3v3ys-n8BJmm48Rn3IWYFZp2BNzgtiWanLp60rW79g9r8jdzqUAgLeD37lGOgo9dJcAAAF9B2MMmw

위의 인가코드입니다!

해당 인가코드로 로그를 확인 못했는데요.

요청온 로그들을 보니 크게 두가지 이유로 에러 발생하고 있습니다.

(1) 토큰요청 시, 인가 코드가 undefined로 넘어오고 있습니다.
(2) 토큰요청 시, 인가 코드를 이용해 다시 토큰 요청하여 에러 발생하는 경우가 있습니다.

에러 응답의 Body 를 확인하시면 좀더 자세한 정보를 전달 받을 수 있습니다.

참고 부탁드려요.

에러가 있어서 그 부분을 수정했구요
아래 인가코드를 새로 발급받아 다시 토큰 요청을 해도
TcJylExv9RPtqDetM4DnEdvXCR0R7h2jfa9wowMGfGzflEn2jk8BC1a99m-MNVqUfi-Auwo9cxcAAAF9B58Gqw

계속 아래처럼 401에러가 뜹니다

{
  status: 401,
  statusText: 'Unauthorized',
  headers: {
    date: 'Wed, 10 Nov 2021 02:13:30 GMT',
    'content-type': 'application/json;charset=utf-8',
    'transfer-encoding': 'chunked',
    connection: 'close',
    pragma: 'no-cache',
    'www-authenticate': 'Bearer realm="oauth", error="invalid_client", error_description="Bad client credentials"',
    'cache-control': 'no-store',
    'x-xss-protection': '1; mode=block',
    'x-frame-options': 'DENY',
    'x-content-type-options': 'nosniff',
    'access-control-allow-origin': '*',
    'access-control-allow-methods': 'GET, POST, OPTIONS',
    'access-control-allow-headers': 'Authorization, KA, Origin, X-Requested-With, Content-Type, Accept'
  },
  config: {
    url: 'https://kauth.kakao.com/oauth/token',
    method: 'post',
    data: '{"grant_type":"authorization_code","client_id":"8feb07aa468832389aee480b6a4d2d59","redirect_uri":"http://localhost:3000/v1/auth/login/kakao","code":"TcJylExv9RPtqDetM4DnEdvXCR0R7h2jfa9wowMGfGzflEn2jk8BC1a99m-MNVqUfi-Auwo9cxcAAAF9B58Gqw"}',
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
      'User-Agent': 'axios/0.21.4',
      'Content-Length': 237
    },
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus],
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    }
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'kauth.kakao.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'kauth.kakao.com',
      _readableState: [ReadableState],
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular *1],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: 149,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object],
      [Symbol(RequestTimeout)]: undefined
    },
    _header: 'POST /oauth/token HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/x-www-form-urlencoded;charset=utf-8\r\n' +
      'User-Agent: axios/0.21.4\r\n' +
      'Content-Length: 237\r\n' +
      'Host: kauth.kakao.com\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    path: '/oauth/token',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 401,
      statusMessage: 'Unauthorized',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'https://kauth.kakao.com/oauth/token',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(RequestTimeout)]: undefined
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'kauth.kakao.com',
    protocol: 'https:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 237,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://kauth.kakao.com/oauth/token',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      'user-agent': [Array],
      'content-length': [Array],
      host: [Array]
    }
  },
  data: {
    error: 'invalid_client',
    error_description: 'Bad client credentials',
    error_code: 'KOE010'
  }
}

혹시 client secret을 활성화한적 없는데 현재 활성화되어있는 상태인가요??

Client Secret을 설정하지 않았는데 Bad client credentials KOE010에러가 발생하는 것은
Request가 훼손되어 Body가 전달되지 않았을때입니다.


최근 로그상 해당 디벨로퍼스앱 토큰요청이 없는 걸 보니, 소스 수정 후 Request Body 가 제대로 전달 안되는 것 같습니다.

확인 부탁드려요.

Request body를 전달하려면 form 데이터로 인코딩이 필요하다고해서
makeFormData 함수를 만들어 인코딩하는 로직을 추가했습니다.

현재 KaKao의 토큰 요청 api를
아래의 자체 api url을 통해서 호출하고 있고
http://localhost:3000/v1/auth/login/kakao
이 url을 호출하면 아래의 함수가 호출됩니다.

  async getKakaoToken(code:string) {    
    const makeFormData = params => {
      const searchParams = new URLSearchParams()
      Object.keys(params).forEach(key => {
        searchParams.append(key, params[key])
      })

      return searchParams
    }
    return await axios({   
      method: 'POST',
      headers: {
        'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
      },
      url: 'https://kauth.kakao.com/oauth/token',
      data: makeFormData({
        grant_type: 'authorization_code',
        client_id: "43c9642fc1542525ba497a549de4a6b8",
        redirect_uri: "http://localhost:3000/kakao/token",
        code: code
      })
    });
  }

여기에 인가코드
8F-dSjCq9tftqleHM1hi332e8lpy3YVqkZ5cNPI4jhMuuQ1IqTxGhwDcvpaWoyBnJUVC3Qo9dNkAAAF9B8Tc8A 로
아래 함수에 보내 토큰 요청을 하면

[Nest] 2016  - 2021. 11. 10. 오전 11:54:51   ERROR [ExceptionsHandler] Converting circular structure to JSON
    --> starting at object with constructor 'ClientRequest'
    |     property 'socket' -> object with constructor 'TLSSocket'
    --- property '_httpMessage' closes the circle
TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'ClientRequest'
    |     property 'socket' -> object with constructor 'TLSSocket'
    --- property '_httpMessage' closes the circle
    at JSON.stringify (<anonymous>)
    at stringify (C:\Users\dexign\Desktop\jebs-api\node_modules\express\lib\response.js:1123:12)
    at ServerResponse.json (C:\Users\dexign\Desktop\jebs-api\node_modules\express\lib\response.js:260:14)
    at ExpressAdapter.reply (C:\Users\dexign\Desktop\jebs-api\node_modules\@nestjs\platform-express\adapters\express-adapter.js:32:57)
    at RouterResponseController.apply (C:\Users\dexign\Desktop\jebs-api\node_modules\@nestjs\core\router\router-response-controller.js:14:36)
    at C:\Users\dexign\Desktop\jebs-api\node_modules\@nestjs\core\router\router-execution-context.js:175:48
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at C:\Users\dexign\Desktop\jebs-api\node_modules\@nestjs\core\router\router-execution-context.js:47:13
    at C:\Users\dexign\Desktop\jebs-api\node_modules\@nestjs\core\router\router-proxy.js:9:17

이런 에러가 뜨는데 redirect_uri 때문에 생기더라구요

rediirect_uri를
http://localhost:3000/kakao/token
이렇게 설정한 상황이고, 인가코드 요청 api와 토큰 요청 api에서 redirect_uri도 동일하게 하였습니다.
혹시 어떤 문제인지 알 수 있을까요?

기재해주신 인가코드로 로그를 보니 토큰이 정상 발급되었는데요.
첨부해주신 로그에 아래 메시지는 json컨버팅 오류 같은데…
확인해보시겠어요?
‘Converting circular structure to JSON’

아 마지막에 이게 없어서 났던 오류네요 ㅠ

.then(res => res.data);
  async getKakaoToken(code:string) {    
    const makeFormData = params => {
      const searchParams = new URLSearchParams()
      Object.keys(params).forEach(key => {
        searchParams.append(key, params[key])
      })
      return searchParams;
    }
    return await axios({  
      method: 'POST',
      headers: {
        'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
      },
      url: 'https://kauth.kakao.com/oauth/token',
      data: makeFormData({
        grant_type: 'authorization_code',
        client_id: "43c9642fc1542525ba4***",
        redirect_uri: "http://localhost:3000/v1/auth/login/kakao/receive",
        code: code
      })
    }).then(res => res.data);

마지막에 then(res => res.data)를 붙이니까 정상작동 됩니다
감사합니다!

좋아요 1