Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain Google service account access token javascript

Tags:

I'm trying to set up an analytics dashboard of my site for my leadership to view site usage. I don't want them to have to have a google account or to add them individual to see the results.

I've set up a service account and OAuth2 access. All the tutorials I find show code like this:

gapi.analytics.auth.authorize({   clientid: 'Service account client ID',   serverAuth: {       access_token: 'XXXXXXXXXXXXXXXXX' } 

And all the documentation talks about "...once you recieve your access token...." But none of them actually say how to get that! I see Certificate Fingerprints, Public key fingerprints. I also see how to generate JSON and P12 keys. I don't see how to generate the access token.

Can someone explain how to do this?

I found this. It explains that I need the key file and that it is a bad idea, but doesn't say how to actually do it.

I also found this. But I don't know anything about Node.js and I'm hoping that is just one possible route?

like image 629
Rothrock Avatar asked Feb 26 '15 20:02

Rothrock


People also ask

How do I get access token for Google services?

To obtain an access token that grants an application delegated access to a resource, include the email address of the user in the JWT claim set as the value of the sub field. The email address of the user for which the application is requesting delegated access.

How can I get GCP token from service account?

Use your service account's key JSON file to get an access token to call Google APIs. Good for seeing how things work, including the creation of JWT token. To create a JWT token, you can replace create-jwt-token.sh script with tools like step.

How do I get my Google access token email API?

If this scope is included while you generate the refresh token, you should be able to get the email address of the authenticating user by making the following request: https://www.googleapis.com/oauth2/v2/userinfo?access_token="YOUR_ACCESS_TOKEN". You can try this out in the API explorer.


2 Answers

Finally got it working! Using kjur's jsjws pure JavaScript implementation of JWT. I used this demo as the basis for generating the JWT to request the token. Here are the steps

In the Google Developers console I created a service account. Here are instructions for that

In the Google API console I added the service account to the credentials. I then generated a new JSON key. This gives me my private key in plain text format.

I then followed these instructions from google on making an authorized API call using HTTP/REST.

This is the required header information.

var pHeader = {"alg":"RS256","typ":"JWT"} var sHeader = JSON.stringify(pHeader); 

And the claim set is something like this. (This is using syntax that is supplied by the KJUR JWT library described above.)

var pClaim = {}; pClaim.aud = "https://www.googleapis.com/oauth2/v3/token"; pClaim.scope = "https://www.googleapis.com/auth/analytics.readonly"; pClaim.iss = "<[email protected]"; pClaim.exp = KJUR.jws.IntDate.get("now + 1hour"); pClaim.iat = KJUR.jws.IntDate.get("now");  var sClaim = JSON.stringify(pClaim); 

The the controversial bit is putting my private key into the client side code. For this usage it isn't that bad (I don't think.) First, the site is behind our corporate firewall, so who is going to "hack" it? Second, even if someone did get it, the service account's only authorization is to view our analytics data -- which is the purpose of my dashboard is that anybody who visits the page can view our analytics data. Not going to post the private key here, but basically like so.

var key = "-----BEGIN PRIVATE KEY-----\nMIIC....\n-----END PRIVATE KEY-----\n";`enter code here` 

Then generated a signed JWT with

 var sJWS = KJUR.jws.JWS.sign(null, sHeader, sClaim, key); 

After that I used XMLHttpRequest to call the google API. I tried to use FormData with the request but that didn't work. So the old(er) school

var XHR = new XMLHttpRequest(); var urlEncodedData = ""; var urlEncodedDataPairs = [];  urlEncodedDataPairs.push(encodeURIComponent("grant_type") + '=' + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer")); urlEncodedDataPairs.push(encodeURIComponent("assertion") + '=' + encodeURIComponent(sJWS)); urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+');  // We define what will happen if the data are successfully sent XHR.addEventListener('load', function(event) {     var response = JSON.parse(XHR.responseText);     token = response["access_token"] });  // We define what will happen in case of error XHR.addEventListener('error', function(event) {     console.log('Oops! Something went wrong.'); });  XHR.open('POST', 'https://www.googleapis.com/oauth2/v3/token'); XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); XHR.send(urlEncodedData) 

After that I have my access token and I can follow these tutorials on using the embed API, but authorizing like so:

gapi.analytics.auth.authorize({     serverAuth: {         access_token: token     } }); 

Don't forget that you have to give the service account permission to view the content, just like any other user. And of course, it would be a really bad idea if the service account was authorized to do anything other than read only.

There are probably also issues with regards to timing and token expiring that I will run into, but so far so good.

like image 125
Rothrock Avatar answered Oct 19 '22 00:10

Rothrock


You can use the official (and alpha) Google API for Node.js to generate the token. It's helpful if you have a service account.

On the server:

npm install -S googleapis 

ES6:

import google from 'googleapis' import googleServiceAccountKey from '/path/to/private/google-service-account-private-key.json' // see docs on how to generate a service account  const googleJWTClient = new google.Auth.JWT(   googleServiceAccountKey.client_email,   null,   googleServiceAccountKey.private_key,   ['https://www.googleapis.com/auth/analytics.readonly'], // You may need to specify scopes other than analytics   null, )  googleJWTClient.authorize((error, access_token) => {    if (error) {       return console.error("Couldn't get access token", e)    }    // ... access_token ready to use to fetch data and return to client    // even serve access_token back to client for use in `gapi.analytics.auth.authorize` }) 
like image 36
hwrod Avatar answered Oct 19 '22 00:10

hwrod