Skip to main content
scottm29310603
Inspiring
June 3, 2019
Question

CEP google Oauth

  • June 3, 2019
  • 3 replies
  • 6545 views

I have been working CEP that can pull data from a public google sheet.

This works.

I now want, after the data has been retrieved and the script has run to change a cell value so when it goes through the loop. It will skip anything that isn't specified.

This appears to require Oauth, which i've been testing with using a http://localhost . I got this all working really well.

Now importing the code back into my panel. I realised a few things. It's not a localhost.

This isn't being sold and is bespoke for myself and the company I work for, so I don't need a webserver/website to run it off (Or do I?)

How can I get my CEP Panel get passed the Oauth so I can keep my sheets private and use the Google API (Unless anyone else has alternative suggestions)

This topic has been closed for replies.

3 replies

scottm29310603
Inspiring
June 18, 2019

It opens a popup window, but this does have a url if you hover over it.

So I'm assuming part of it opens a new window with the http:// and content preloaded client ID etc similar to my "href" example.

I don't have my machine in front of me, but I do know that I spotted it had a url when hovering, that's what made me try href

scottm29310603
Inspiring
June 19, 2019

Hey Justin,

Hopefully this is the one.

I've figured out how to get my token, that was actually easier than I thought.

Preconfigured link that returns my google code 4/bldfnaksjbdfgoajbjbaouborve;jasdvpobad (I've made this up)

Then I use $.Ajax to create my token.

The next part is reading the token

fs.readFile(TOKEN_PATH, (err, token) => {

if (err) return getAccessToken(oAuth2Client, callback);

oAuth2Client.setCredentials(JSON.parse(token));

callback(oAuth2Client);

});

}

Can this only be done via node? fs.readFile appears to be the only way that I can find info on.

This is the last part I'm struggling with, then I should be in.

Justin Taylor-Hyper Brew
Community Expert
Community Expert
June 19, 2019

Glad to hear you found some solutions to that! You're past the hard part, the rest is easy.

You can read files in a variety of ways, my favorite is

var contents = fs.readFileSync(path, 'utf8');

and then you'll want to parse that token file

var token = JSON.parse(contents)

There are also some built-in read methods in CEP like cep.fs.readFile(), but they seem less reliable, I'd stick with the Node.js methods.

scottm29310603
Inspiring
June 6, 2019

Low and behold, the first time I google search "Node google api reference" first thing I get is what you've suggested.

I have googled everything like "Node Google API CEP" or "Node CEP Oauth", nothing. So I'll properly look at this next week when I don't have deadlines to complete and hopefully I'll have a fully working plugin.

Thank you again for pointing me in the right direction.

Justin Taylor-Hyper Brew
Community Expert
Community Expert
June 6, 2019

I think this is the example I built my module from:https://developers.google.com/drive/api/v3/quickstart/nodejs

Google Drive | Node.js Quickstart

Node.js seems daunting at first, but with CEP it doesn't have to be that complicated. Just enable Node.js and mixed content in your manifest.xml,

<Resources>

    <MainPath>./ui/index.html</MainPath>

    <ScriptPath>./main.jsx</ScriptPath>

    <CEFCommandLine>

          <Parameter>--enable-nodejs</Parameter>

          <Parameter>--mixed-context</Parameter>

    </CEFCommandLine>

</Resources>

install Node.js on your machine, and you can start npm installing and requiring packages.

And yes, you'll need to require the module with a statement like var {google} = require('googleapis'); or equivalent.

scottm29310603
Inspiring
June 11, 2019

Hey Justin,

I think I'm doing something wrong. When I launch the script, I don't get a new window to sign in and get my token.

I've done tests with my terminal on localhost, this works, but not in the panel. I tried resorting to opening my invisible html server in default browser to do what I needed, but even that didn't work.

Any suggestions on what I could be doing wrong?

The node works fine, everything I alert and console.log suggests the node works fine, even testing for importing an image. However it doesn't seem to work for the googleapi.

Have you got any references to the index.js and the html that shows how it launches the browser that allows you to grab the token. Or am I missing something.

Justin Taylor-Hyper Brew
Community Expert
Community Expert
June 4, 2019

You'll probably have better luck with these types of questions in a Google forum, but I did some Google Sheets Oauth stuff about a year ago. Where in your authentication are you running into an issue? Can you post a code snippet of what's breaking?

scottm29310603
Inspiring
June 5, 2019

Morning Justin,

My code works fine in a localserver

I don't have a website, so I use localhost (this works fine) in my root web server on my Mac for testing, the Oauth works fine. It retrieves the data and writes back perfectly.

So I thought I could just copy and paste this code into my CEP, soon as I hit sign in...Nothing.

I realised, my CEP doesn't sit in my web server folder on my Mac. So it's not connecting to anything as the plugin isn't localhost.

Googles security requires that, so I don't know how now that I've moved my code out of my local server into my extension panel, how to now contact and get passed Oauth.

Someone has suggested node and ngrok. Both allow you to create a localhost and port, which look likes to be a possibility, but it's a little bit over my expertise. Some appear to use an access token, but again this is slightly going over my head because I'm new to this (I'm amazed I've gotten this far, when I've taught myself all this in the last 3-6 months.)

But there's not much in examples or tutorials, just bits here and there.

Below is my code, this works great in my local server. It's just how to get it to work with my CEP that is the issue.

<html>

  <head></head>

  <body>

    <script>

i=2;

    function partOne(){

      //for (i = 2; i <= 5; i++) {

      var request = gapi.client.sheets.spreadsheets.values.get({

        spreadsheetId: 'PUT SHEET ID HERE',

        range: 'Sheet1!C'++''

}).then((response) => {

  //console.log(response.result)

  if(response.result.values == "Ready"){

    makeApiCall(i);

  }else{

    console.log();

  }

  i++;

  if(i <= 6) partOne()

});

    //}

    }

    function makeApiCall() {

      var request = gapi.client.sheets.spreadsheets.values.update({

        spreadsheetId: 'PUT SHEET ID HERE',

        range: 'Sheet1!C'++'',

        valueInputOption: 'USER_ENTERED',

        values: [ ["DONE"] ]

}).then(function(response) {

    console.log(response);

});

    }

    function initClient() {

      var API_KEY = 'PUT API_KEY HERE';  // TODO: Update placeholder with desired API key.

      var CLIENT_ID = 'PUT CLIENT_ID HERE';  // TODO: Update placeholder with desired client ID.

      // TODO: Authorize using one of the following scopes:

      //   'https://www.googleapis.com/auth/drive'

      //   'https://www.googleapis.com/auth/drive.file'

      //   'https://www.googleapis.com/auth/spreadsheets'

      var SCOPE = 'https://www.googleapis.com/auth/spreadsheets';

      gapi.client.init({

        'apiKey': API_KEY,

        'clientId': CLIENT_ID,

        'scope': SCOPE,

        'discoveryDocs': ['https://sheets.googleapis.com/$discovery/rest?version=v4'],

      }).then(function() {

        gapi.auth2.getAuthInstance().isSignedIn.listen(updateSignInStatus);

        updateSignInStatus(gapi.auth2.getAuthInstance().isSignedIn.get());

      });

    }

    function handleClientLoad() {

      gapi.load('client:auth2', initClient);

    }

    function updateSignInStatus(isSignedIn) {

      if (isSignedIn) {

        partOne();

        //makeApiCall();

        //setTimeout(function(){partTwo()},5000);

      }

    }

    function handleSignInClick(event) {

      gapi.auth2.getAuthInstance().signIn();

    }

    function handleSignOutClick(event) {

      gapi.auth2.getAuthInstance().signOut();

    }

    </script>

    <script async defer src="https://apis.google.com/js/api.js"

      onload="this.onload=function(){};handleClientLoad()"

      onreadystatechange="if (this.readyState === 'complete') this.onload()">

    </script>

    <button id="signin-button" onclick="handleSignInClick()">Sign in</button>

    <button id="signout-button" onclick="handleSignOutClick()">Sign out</button>

  </body>

</html>

Justin Taylor-Hyper Brew
Community Expert
Community Expert
June 5, 2019

Yea I used the token method, saves you having to log in every time. You will need Node.js enabled and you can download and require the google-api module with

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

They have tuts for it up on the Google site, but here's my code for reference if you want:

/**

* the @ gdrive module allows uploading to Google Drive once authenticated

* A configuration and token file is required.

* @param {Int} number number of entries to return.

*/

var gdrive = {};

gdrive.SCOPES = ['https://www.googleapis.com/auth/drive.file'];

gdrive.TOKEN_PATH = 'token.json';

gdrive.AUTH = {};

gdrive.instance;

gdrive.build = function(token){

return new Promise((resolve, reject) => {

// Load client secrets from a local file.

fs.readFile(path.join(__dirname, 'credentials.json'), (err, content) => {

if (err) return console.log('Error loading client secret file:', err);

// Authorize a client with credentials, then call the Google Drive API.

gdrive.authorize(JSON.parse(content), token, gdrive.create);

setTimeout(function(){resolve(true);}, 1000);

});

});

};

/**

* Create an OAuth2 client with the given credentials, and then execute the

* given callback function.

* @param {Object} credentials The authorization client credentials.

* @param {function} callback The callback to call with the authorized client.

*/

gdrive.authorize = function(credentials, token, callback) {

const {client_secret, client_id, redirect_uris} = credentials.installed;

gdrive.oAuth2Client = new google.auth.OAuth2(

client_id, client_secret, redirect_uris[0]);

gdrive.oAuth2Client.setCredentials(token);

callback(gdrive.oAuth2Client);

};

/**

* Get and store new token after prompting for user authorization, and then

* execute the given callback with the authorized OAuth2 client.

* @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.

* @param {getEventsCallback} callback The callback for the authorized client.

*/

gdrive.getAccessToken = function(oAuth2Client, callback) {

const authUrl = oAuth2Client.generateAuthUrl({

access_type: 'offline',

scope: gdrive.SCOPES,

});

console.log('Authorize this app by visiting this url:', authUrl);

const rl = readline.createInterface({

input: process.stdin,

output: process.stdout,

});

// rl.question('Enter the code from that page here: ', (code) => {

prompt({

title: 'Google Token',

label: 'Enter the code from that page here:',

value: '',

}).then((value) => {

if(value === null) {

console.log('user cancelled');

} else {

console.log('result', value);

var code = value;

rl.close();

oAuth2Client.getToken(code, (err, token) => {

if (err) return console.error('Error retrieving access token', err);

oAuth2Client.setCredentials(token);

// Store the token to disk for later program executions

fs.writeFile(gdrive.TOKEN_PATH, JSON.stringify(token), (err) => {

if (err) console.error(err);

console.log('Token stored to', gdrive.TOKEN_PATH);

});

callback(oAuth2Client);

});

}

}).catch(console.error);

// });

};

/**

* Creates a Google Drive instance to be used for uploads/downloads

* @param {google.auth.OAuth2} auth An authorized OAuth2 client.

*/

gdrive.create = function(auth){

gdrive.instance = google.drive({version: 'v3', auth});

};

And then you pass in your credentials.json token with: gdrive.build(token)