Clay Smith
Clay Smith

Reputation: 43

Cloud Function to Authenticate a User

I am attempting to authenticate a user to access various scopes in the user Gsuite. I can run the code locally but I cannot seem to get it accepted as a cloud function.

I have tried deploying with firebase and with gcloud. I have checked my eslint settings.

This code is coming from https://github.com/googleapis/google-api-nodejs-client/blob/master/README.md#oauth2-client

'use strict';

const fs = require('fs');
const path = require('path');
const http = require('http');
const url = require('url');
const opn = require('open');
const destroyer = require('server-destroy');

const {google} = require('googleapis');

/**
 * To use OAuth2 authentication, we need access to a a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.  To get these credentials for your application, visit https://console.cloud.google.com/apis/credentials.
 */
const keyPath = path.join(__dirname, 'credentials.json');
let keys = {redirect_uris: ['']};
if (fs.existsSync(keyPath)) {
  keys = require(keyPath).web;
}

/**
 * Create a new OAuth2 client with the configured keys.
 */
const oauth2Client = new google.auth.OAuth2(
  keys.client_id,
  keys.client_secret,
  `http://localhost:3000/oauth2callback`
);

/**
 * This is one of the many ways you can configure googleapis to use authentication credentials.  In this method, we're setting a global reference for all APIs.  Any other API you use here, like google.drive('v3'), will now use this auth client. You can also override the auth client at the service and method call levels.
 */
google.options({auth: oauth2Client});
const scopes = ['https://www.googleapis.com/auth/documents'];
/**
 * Open an http server to accept the oauth callback. In this simple example, the only request to our webserver is to /callback?code=<code>
 */
async function authenticate(){
    // grab the url that will be used for authorization
    const authorizeUrl = oauth2Client.generateAuthUrl({
      access_type: 'offline',
      scope: scopes
    });

    const server = http.createServer(async (req, res) => {
        try {
          if (req.url.indexOf('/oauth2callback') > -1) {
            const qs = new url.URL(req.url, 'http://localhost:3000').searchParams;
            res.end('Authentication successful! Please return to the console.');
            server.destroy();
            const {tokens} = await oauth2Client.getToken(qs.get('code'));
            oauth2Client.credentials = tokens; // eslint-disable-line require-atomic-updates
            resolve(oauth2Client);
          }
        } catch (e) {
          reject(e);
        }
      })

      .listen(3000, () => {
        // open the browser to the authorize url to start the workflow
        opn(authorizeUrl, {wait: false}).then(cp => cp.unref())
        .catch(
            error => { 
            console.log(error);
        });
      });

    destroyer(server)
     .then(client => runSample(client)).catch(
         error => { 
         console.log(error);
       });
};
module.exports.authenticate=authenticate;

async function runSample(client) {
  // retrieve user profile
  console.log(client);
  const docs = google.docs({
    version: 'v1',
    auth: client
  });
  const createResponse = await docs.documents.create({
    requestBody: {
      title: 'Your new document!',
    },
  });
}

I expect it to load as a cloud function to firebase or gcloud. However: Firebase returns "Deploy complete" but it never shows in the functions. gcloud returns "SyntaxError: Unexpected token function" with the word function indicated in "async function authenticate(){"

I'm new to node.js and may be missing something really obvious to others.

Upvotes: 1

Views: 1385

Answers (1)

Mayeru
Mayeru

Reputation: 1094

You will never get User Credentials (Client ID/Client Secret) to work in Cloud Functions (meaning authenticate and create credentials). OAuth requires a web browser and a human. Neither one exists in Cloud Functions. Use a Service Account instead. – John Hanley

Upvotes: 1

Related Questions