I am trying to get the youtube transcription with youtube API on the Express.js server. From what I understand, I need to use the client id for this, so I am trying to authenticate to google API. For this purpose I use quickstart.js from google docs and Express listener on redirect_uri to handle authentication:
interface GoogleOAuthTokenResponse { access_token: string token_type: string expires_in: number id_token: string refresh_token?: string}// Handle authentication callback from Googleapp.get('/auth/google/callback', async (req, res, next) => { const code = req.query.code const response = await axios.post<GoogleOAuthTokenResponse>('https://oauth2.googleapis.com/token', { code, client_id: process.env.YOUTUBE_CLIENT_ID, client_secret: process.env.YOUTUBE_CLIENT_SECRET, redirect_uri: process.env.YOUTUBE_REDIRECT_URI, grant_type: 'authorization_code' }, { headers: {'Content-Type': 'application/x-www-form-urlencoded' } }) const accessToken = response.data.access_token // Now that we have the access token and id token, we can use them to call Google API services const googleResponse = await axios.get('https://www.googleapis.com/some_google_api', { headers: { Authorization: `Bearer ${accessToken}` } }) res.send(googleResponse.data)})
But I get the following error:
/Users/demian/Desktop/work/youtube-navigator/server/node_modules/axios/lib/core/settle.js:19 reject(new AxiosError( ^AxiosError: Request failed with status code 400 at settle (/Users/demian/Desktop/work/youtube-navigator/server/node_modules/axios/lib/core/settle.js:19:12) at Unzip.handleStreamEnd (/Users/demian/Desktop/work/youtube-navigator/server/node_modules/axios/lib/adapters/http.js:548:11) at Unzip.emit (node:events:525:35) at Unzip.emit (node:domain:489:12) at endReadableNT (node:internal/streams/readable:1359:12) at processTicksAndRejections (node:internal/process/task_queues:82:21) { code: 'ERR_BAD_REQUEST', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http' ], transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: [Function], Blob: [class Blob] }, validateStatus: [Function: validateStatus], headers: AxiosHeaders { Accept: 'application/json, text/plain, */*','Content-Type': 'application/x-www-form-urlencoded','User-Agent': 'axios/1.3.2','Content-Length': '313','Accept-Encoding': 'gzip, compress, deflate, br' }, method: 'post', url: 'https://oauth2.googleapis.com/token', data: 'code=4%2F0AWtgzh5yCRs6xsZCCAEUhJGVTNE22-xpI9u3KaaCrgGl_wI618yJSGHUta53Z-w5VB7_Lw&client_id=252564275188-g55c2qnu6ajii45m3d154uuj9fnhlbfb.apps.googleusercontent.com&client_secret=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&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fgoogle%2Fcallback&grant_type=authorization_code' }, 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)], finish: [Function: requestOnFinish] }, _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: true, _last: false, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: '313', _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: false, _SNICallback: null, servername: 'oauth2.googleapis.com', alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object: null prototype], _eventsCount: 9, connecting: false, _hadError: false, _parent: null, _host: 'oauth2.googleapis.com', _closeAfterHandlingError: false, _readableState: [ReadableState], _maxListeners: undefined, _writableState: [WritableState], allowHalfOpen: false, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: [TLSWrap], _requestCert: true, _rejectUnauthorized: true, timeout: 5000, parser: null, _httpMessage: null, [Symbol(res)]: [TLSWrap], [Symbol(verified)]: true, [Symbol(pendingSession)]: null, [Symbol(async_id_symbol)]: -1, [Symbol(kHandle)]: [TLSWrap], [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: [Timeout], [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(kCapture)]: false, [Symbol(kSetNoDelay)]: false, [Symbol(kSetKeepAlive)]: true, [Symbol(kSetKeepAliveInitialDelay)]: 1, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0, [Symbol(connect-options)]: [Object] }, _header: 'POST /token HTTP/1.1\r\n'+'Accept: application/json, text/plain, */*\r\n'+'Content-Type: application/x-www-form-urlencoded\r\n'+'User-Agent: axios/1.3.2\r\n'+'Content-Length: 313\r\n'+'Accept-Encoding: gzip, compress, deflate, br\r\n'+'Host: oauth2.googleapis.com\r\n'+'Connection: keep-alive\r\n'+'\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: Agent { _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object: null prototype], requests: [Object: null prototype] {}, sockets: [Object: null prototype] {}, freeSockets: [Object: null prototype], keepAliveMsecs: 1000, keepAlive: true, 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: '/token', _ended: true, res: IncomingMessage { _readableState: [ReadableState], _events: [Object: null prototype], _eventsCount: 4, _maxListeners: undefined, socket: null, httpVersionMajor: 1, httpVersionMinor: 1, httpVersion: '1.1', complete: true, rawHeaders: [Array], rawTrailers: [], aborted: false, upgrade: false, url: '', method: null, statusCode: 400, statusMessage: 'Bad Request', client: [TLSSocket], _consuming: true, _dumped: false, req: [Circular *1], responseUrl: 'https://oauth2.googleapis.com/token', redirects: [], [Symbol(kCapture)]: false, [Symbol(kHeaders)]: [Object], [Symbol(kHeadersCount)]: 30, [Symbol(kTrailers)]: null, [Symbol(kTrailersCount)]: 0 }, aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'oauth2.googleapis.com', protocol: 'https:', _redirectable: Writable { _writableState: [WritableState], _events: [Object: null prototype], _eventsCount: 3, _maxListeners: undefined, _options: [Object], _ended: true, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 313, _requestBodyBuffers: [], _onNativeResponse: [Function (anonymous)], _currentRequest: [Circular *1], _currentUrl: 'https://oauth2.googleapis.com/token', [Symbol(kCapture)]: false }, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kEndCalled)]: true, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] { accept: [Array],'content-type': [Array],'user-agent': [Array],'content-length': [Array],'accept-encoding': [Array], host: [Array] }, [Symbol(errored)]: null, [Symbol(kUniqueHeaders)]: null }, response: { status: 400, statusText: 'Bad Request', headers: AxiosHeaders { date: 'Tue, 07 Feb 2023 12:04:34 GMT', expires: 'Mon, 01 Jan 1990 00:00:00 GMT', pragma: 'no-cache','cache-control': 'no-cache, no-store, max-age=0, must-revalidate','content-type': 'application/json; charset=utf-8', vary: 'Origin, X-Origin, Referer', server: 'scaffolding on HTTPServer2','x-xss-protection': '0','x-frame-options': 'SAMEORIGIN','x-content-type-options': 'nosniff','alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000','transfer-encoding': 'chunked' }, config: { transitional: [Object], adapter: [Array], transformRequest: [Array], transformResponse: [Array], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: [Object], validateStatus: [Function: validateStatus], headers: [AxiosHeaders], method: 'post', url: 'https://oauth2.googleapis.com/token', data: 'code=4%2F0AWtgzh5yCRs6xsZCCAEUhJGVTNE22-xpI9u3KaaCrgGl_wI618yJSGHUta53Z-w5VB7_Lw&client_id=252564275188-g55c2qnu6ajii45m3d154uuj9fnhlbfb.apps.googleusercontent.com&client_secret=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&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fgoogle%2Fcallback&grant_type=authorization_code' }, request: <ref *1> ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: true, _last: false, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: '313', _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: true, socket: [TLSSocket], _header: 'POST /token HTTP/1.1\r\n'+'Accept: application/json, text/plain, */*\r\n'+'Content-Type: application/x-www-form-urlencoded\r\n'+'User-Agent: axios/1.3.2\r\n'+'Content-Length: 313\r\n'+'Accept-Encoding: gzip, compress, deflate, br\r\n'+'Host: oauth2.googleapis.com\r\n'+'Connection: keep-alive\r\n'+'\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: [Agent], socketPath: undefined, method: 'POST', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/token', _ended: true, res: [IncomingMessage], aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'oauth2.googleapis.com', protocol: 'https:', _redirectable: [Writable], [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kEndCalled)]: true, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kUniqueHeaders)]: null }, data: { error: 'invalid_grant', error_description: 'Bad Request' } }}
I checked few times that my env variables are correct. So I think this is problem with my code.Maybe this is stupid question, but I really couldn't understand what I do incorrectly. What to do?