title: Google auth hanging waiting for response
body: <p>Log of execution:</p>
  
  <blockquote>
    <p>inside authorize() function ------------------------<br>
    inside readAuth2TokensFromFile() function ------------------------<br>
    Error reading Tokens from a file:./credentials/token.json 
    inside getNewTokensFromGoogleCLI() function ------------------------<br>
    Authorize this app by visiting this (Google login) url: <a href="https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&amp;scope=" rel="nofollow noreferrer">https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&amp;scope=</a>...<br>
    inside getAnswerOn(question) function ------------------------</p>
  </blockquote>
  
  <p>...waiting for response from Google CLI...</p>
  
  <p>The issue in this function calling readLineInterface:</p>
  
  <pre><code>/**
   * @param {string} query The question to ask.
   */
  function getAnswerOn(question) {
    console.log("inside getAnswerOn(question) function ------------------------");
    return new Promise((resolve) =&gt; {
      //https://millermedeiros.github.io/mdoc/examples/node_api/doc/readline.html
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });
  
      rl.question(question, (answer) =&gt; {
        console.log("Answer received succesfully!");
        rl.close();
        process.stdin.destroy();
        resolve(answer);
      });
  
    })
  }
  </code></pre>
  
  <p>Full source code of OAuth2Authorizer.js file:</p>
  
  <pre><code>//Based on https://stackoverflow.com/questions/54882145/is-there-an-async-await-node-js-google-auth-module
  //OAuth2Authorizer with Promises
  'use strict'
  const fs = require('fs');
  const readline = require('readline');
  
  const functions = require('firebase-functions');
  const { google } = require('googleapis');
  
  //Go to the Google Cloud Dashboard: APIs and Services/ Credentials panel: 
  //https://console.cloud.google.com/apis/credentials
  //OAuth2 Client Credentials (Other):
  const KEY = require("./credentials/oauth2.key.json").web;
  
  /**
  * Create a new OAuth2 client with the configured keys.
  * https://github.com/googleapis/google-api-nodejs-client
  */
  const oauth2Client = new google.auth.OAuth2(
    KEY.client_id,
    KEY.client_secret,
    KEY.redirect_uris[0]
  );
  
  function getOAuth2Client() {
    console.log("inside getOAuth2Client ----------------------------");
    return oauth2Client
  }
  
  
  /**
   * reading Tokens from a file:
   * @param {string} path Path to a JSON file where the tokens is stored in.
   */
  function readAuth2TokensFromFile(path) {
    console.log("inside readAuth2TokensFromFile() function ------------------------");
    return new Promise((resolve, reject) =&gt; {
      try {
        resolve(JSON.parse(fs.readFileSync(path).toString()));
      } catch (error) {
        console.log("Error reading Tokens from a file:" + path);
        resolve(undefined)
      }
    })
  }
  
  
  /**
   * @param {string} query The question to ask.
   */
  function getAnswerOn(question) {
    console.log("inside getAnswerOn(question) function ------------------------");
    return new Promise((resolve) =&gt; {
      //https://millermedeiros.github.io/mdoc/examples/node_api/doc/readline.html
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });
  
      rl.question(question, (answer) =&gt; {
        console.log("Answer received succesfully!");
        rl.close();
        process.stdin.destroy();
        resolve(answer);
      });
  
    })
  }
  
  
  
  /**
   * Get and store new token after prompting for user authorization, and then
   * execute the given callback with the authorized OAuth2 client.
   * @param {OAuth2Client} oAuth2Client The OAuth2 client to get token for.
   * @param {string[]} scopes Scopes to get authorization for.
   * @param {string} tokenFilePath Path to a JSON file to store the tokens in.
   * @returns {OAuth2Client} terurns updated oAuth2Client
   */
  function getNewTokensFromGoogleCLI(oAuth2Client, scopes, tokenFilePath) {
    console.log("inside getNewTokensFromGoogleCLI() function ------------------------");
    return new Promise((resolve, reject) =&gt; {
  
      const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: scopes,
      });
  
      console.log('Authorize this app by visiting this (Google login) url: ', authUrl);
  
      getAnswerOn("Enter the long code from that page here:").then(answer =&gt; {
        try {
          console.log("trying to get new token (before getToken) ------------------")
          oAuth2Client.getToken(answer, (err, tokens) =&gt; {
            if (!err) {
              // Now tokens contains an access_token and an optional refresh_token. Save them.
              oauth2Client.setCredentials(tokens);
              resolve(oauth2Client) //return updated oauth2Client &lt;-----------------------------
              try {
                // Store the token to disk for later program executions
                fs.writeFileSync(tokenFilePath, JSON.stringify(tokens));
                console.log('Token stored to', tokenFilePath);
              } catch (error) {
                console.error("Error while storing tokens in a file", error);
                reject(new functions.https.HttpsError(error.code, error.message));
              }
            } else {
              console.error('Error in oAuth2Client.getToken() function', err);
              reject(new functions.https.HttpsError(err.code, err.message));
            }
          })
        } catch (error) {
          console.error('Error while trying to retrieve access token', error);
          reject(new functions.https.HttpsError(error.code, error.message));
        }
      })
    })
  }
  
  
  function authorize(key, scopes, tokenPath) {
    console.log("inside authorize() function ------------------------");
    return new Promise((resolve, reject) =&gt; {
      try {
  
        let REQ_SCOPES = scopes;
        if (Array.isArray(scopes)) {
          REQ_SCOPES = scopes.join(" "); //convert an array to the string  
        }
  
        /*
        * Create a new OAuth2 client with the configured keys.
        * https://github.com/googleapis/google-api-nodejs-client
        */
        const oauth2Client = new google.auth.OAuth2(
          key.client_id,
          key.client_secret,
          key.redirect_uris[0]
        );
  
        readAuth2TokensFromFile(tokenPath).then(tokens =&gt; {
          if (tokens) {
            oauth2Client.setCredentials(auth2tokensTokens);
            resolve(oauth2Client);
          } else {
            getNewTokensFromGoogleCLI(oauth2Client, REQ_SCOPES, tokenPath).then(updatedOAauth2Client =&gt; {
              resolve(updatedOAauth2Client)
            })
          }
        })
      } catch (error) {
        console.error('Error while getting a new oauth2Client from key: ', error);
        reject(new functions.https.HttpsError(error.code, error.message));
      }
    })
  }
  
  //Use: const { authorize } = require('./OAuth2Authorizer.js');
  exports.authorize = authorize;
  </code></pre>