get google analytics report by api - node.js

I am making a website like flippa to sell established websites, I want to verify website traffic like flippa do, I searched for how to get reports of visits last 12 months but I can't, what I do make client click on link
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=814867900881-28dlacj0v68nh9suspfjlnvjgscalaql.apps.googleusercontent.com&prompt=consent&redirect_uri=http://localhost:3000/redirect&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.readonly&state=9612
to get code then use that code to get access_token
POST https://accounts.google.com/o/oauth2/token
code=4/gXCN77EWLDCO_fake_p2tvfakezOg6Mn0fakej2vA.giyP3fakejxeAeYFZr95uygvU3j0dumQI&
client_id=104608secret-secret-secret-secret.apps.googleusercontent.com&
client_secret=90V0FAKE_WkFAKExrHCZti&
redirect_uri=http://www.mywebapp.com/oauth2callback&
grant_type=authorization_code
then I get access token
{
"access_token": "ya29.Il-yBwla5jnTECDlX5rbVk_Oq4hireOUmSzeaTWW2BgYYsBCoPn6pKnQVxIUQtGc0BXblEq_2ZQ-zhrrGeL9xYYuSyd8lvRAoPBUVKUN8liBwx-w8ok2oGh2Cknql2ucew",
"expires_in": 3600,
"refresh_token": "1//031hXU_jNeKEECgYIARAAGAMSNwF-L9Irds9iUaPkcGDDOSHP2-8-1FKYBRW1GaBz1fLzEoDnEcNIm89k-bZzYWXAqie5Or-Fg94",
"scope": "https://www.googleapis.com/auth/analytics.readonly",
"token_type": "Bearer"
}
and don't know what I do next and if what I do is the right way
I need the correct way to get user GA reporting

What you have done so far covers your authentication flow. Now you will need to make a call to the Analytics Reporting API and supply the access token you have created.
Here is a reference for setting up your request:
https://developers.google.com/analytics/devguides/reporting/core/v4/rest/v4/reports/batchGet
There are also samples available for how to request data.

Depending on the system you have, this may help. https://developers.google.com/analytics/devguides/reporting/core/v4
In essence, you add the access token in the google client then perform the request.
For node.js, I found this site that does the particular in node.js although this uses JWT. https://flaviocopes.com/google-analytics-api-nodejs/
const { google } = require('googleapis')
const scopes = 'https://www.googleapis.com/auth/analytics.readonly'
const jwt = new google.auth.JWT(process.env.CLIENT_EMAIL, null, process.env.PRIVATE_KEY, scopes)
const view_id = 'XXXXX'
async function getData() {
const response = await jwt.authorize()
const result = await google.analytics('v3').data.ga.get({
'auth': jwt,
'ids': 'ga:' + view_id,
'start-date': '30daysAgo',
'end-date': 'today',
'metrics': 'ga:pageviews'
})
console.dir(result)
}
getData()
Also, google APIs for Node.js for reference: https://www.npmjs.com/package/googleapis
It contains how to set the access token to set to the oauth2Client and use these in the APIs.
Hope this helps :)

Related

How do I call Google Analytics Admin API (for GA4) using an OAuth2 client in node.js?

I've noticed that all the node.js code samples for Google Analytics Admin and Google Analytics Data assume a service account and either a JSON file or a GOOGLE_APPLICATION_CREDENTIALS environment variable.
e.g.
const analyticsAdmin = require('#google-analytics/admin');
async function main() {
// Instantiates a client using default credentials.
// TODO(developer): uncomment and use the following line in order to
// manually set the path to the service account JSON file instead of
// using the value from the GOOGLE_APPLICATION_CREDENTIALS environment
// variable.
// const analyticsAdminClient = new analyticsAdmin.AnalyticsAdminServiceClient(
// {keyFilename: "your_key_json_file_path"});
const analyticsAdminClient = new analyticsAdmin.AnalyticsAdminServiceClient();
const [accounts] = await analyticsAdminClient.listAccounts();
console.log('Accounts:');
accounts.forEach(account => {
console.log(account);
});
}
I am building a service which allows users to use their own account to access their own data, so using a service account is not appropriate.
I initially thought I might be able to use the google-api-node-client -- Auth would be handled by building a URL to redirect and do the oauth dance...
Using google-api-nodejs-client:
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
// generate a url that asks permissions for Google Analytics scopes
const scopes = [
"https://www.googleapis.com/auth/analytics", // View and manage your Google Analytics data
"https://www.googleapis.com/auth/analytics.readonly", // View your Google Analytics data
];
const url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes
});
// redirect to `url` in a popup for the oauth dance
After auth, Google redirects to GET /oauthcallback?code={authorizationCode}, so we collect the code and get the token to perform subsequent OAuth2 enabled calls:
// This will provide an object with the access_token and refresh_token.
// Save these somewhere safe so they can be used at a later time.
const {tokens} = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens);
// of course we need to handle the refresh token too
This all works fine, but is it possible to plug the OAuth2 client from the google-api-node-client code into the google-analytics-admin code?
👉 It looks like I need to somehow call analyticsAdmin.AnalyticsAdminServiceClient() with the access token I've already retrieved - but how?
The simple answer here is don't bother with the Node.js libraries for Google Analytics Admin & Google Analytics Data.
Cut out the middleman and build a very simple wrapper yourself which queries the REST APIs directly. Then you will have visibility on the whole of the process, and any errors made will be your own.
Provided you handle the refresh token correctly, this is likely all you need:
const getResponse = async (url, accessToken, options = {}) => {
const response = await fetch(url, {
...options,
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return response;
};
I use Python but the method could be similar. You should create a Credentials object based on the obtained token:
credentials = google.auth.credentials.Credentials(token=YOUR_TOKEN)
Then use it to create the client:
from google.analytics.admin import AnalyticsAdminServiceClient
client = AnalyticsAdminServiceClient(credentials=credentials)
client.list_account_summaries()

Endpoint to fetch Subreddits of a Reddit Account

I have completed the oauth flow for my third party app against a Reddit account and I've gotten the access token for the account.
Now my next issue is
How can I fetch the subreddits for an account using the access token
I can't seem to figure out the endpoint for that.
Does anyone know the endpoint for that?
Thank you
The Reddit OAuth Docs say that for the /subreddits/mine/(where) endpoint, the subreddits OAuth scope is necessary.
Once that scope is acquired for a user, you can use the following snippets of code to access the list of subscribed subreddits for the user:
View a users subreddits                                                                                
View in Fusebit
// Demonstrate using snooclient and Fusebit
const subscriptions = await redditClient.getSubscriptions().fetchAll();
// OR fetch the first page using a raw HTTP request
// - the User-Agent is necessary, don't forget it!
const access_token = redditClient.fusebit.credentials.access_token;
const httpSubs = await superagent.get(
'https://oauth.reddit.com/subreddits/mine/subscriber')
.set('Authorization', `Bearer ${access_token}`)
.set('User-Agent', 'Fusebit Integration');
const length = httpSubs.body.data.children.length;
ctx.body = {
usingSnoo: `User has ${subscriptions.length} subreddits`,
usingHttp: `The first page has ${length} subreddits`,
};
});

Verify JWT from Google Chat POST request

I have a bot in NodeJS connected to Google Chat using HTTPs endpoints. I am using express to receive requests. I need to verify that all requests come from Google, and want to do this using the Bearer Token that Google Sends with requests.
My problem is that I am struggling to find a way to verify the tokens.
I have captured the token and tried a GET reuqes to https://oauth2.googleapis.com/tokeninfo?id_token=ey... (where ey... is the token start).
Which returns:
"error": "invalid_token",
"error_description": "Invalid Value"
}
I have tried what Google recommends:
var token = req.headers.authorization.split(/[ ]+/);
client.verifyIdToken({
idToken: token[1],
audience: JSON.parse(process.env.valid_client_ids)
}).then((ticket) => {
gchatHandler.handleGChat(req.body, res);
}).catch(console.error);
And get the following error:
Error: No pem found for envelope: {"alg":"RS256","kid":"d...1","typ":"JWT"}
Any idea where I should head from here?
Edit: https://www.googleapis.com/service_accounts/v1/metadata/x509/chat#system.gserviceaccount.com found this, investigating how to use it. The kid matches the one I get.
Worked it out, eventually.
You need to hit: https://www.googleapis.com/service_accounts/v1/metadata/x509/chat#system.gserviceaccount.com to get a JSON file containing the keys linked to their KIDs.
Then when a request arrives, use jsonwebtoken (NPM) to decode the token and extract the KID from the header.
Use the KID to find the matching public key in the response from the website above, then use the verify function to make sure the token matches the public key.
You also need to pass the audience and issuer options to verify, to validate that it is your particular service account hitting the bot.
The solution above maybe the correct for Google Chat, but in my experience Google services (e.g. Google Tasks) use OIDC tokens, which can be validated with verifyIdToken function.
Adding my solution here, since your question/answer was the closest thing I was able to find to my problem
So, In case if you need to sign a request from your own code
on client, send requests with OIDC token
import {URL} from 'url';
import {GoogleAuth} from 'google-auth-library';
// will use default auth or GOOGLE_APPLICATION_CREDENTIALS path to SA file
// you must validate email of this identity on the server!
const auth = new GoogleAuth({});
export const request = async ({url, ...options}) => {
const targetAudience = new URL(url as string).origin;
const client = await auth.getIdTokenClient(targetAudience);
return await client.request({...options, url});
};
await request({ url: 'https://my-domain.com/endpoint1', method: 'POST', data: {} })
on the server, validate OIDC (Id token)
const auth = new OAuth2Client();
const audience = 'https://my-domain.com';
// to validate
const token = req.headers.authorization.split(/[ ]+/)[1];
const ticket = await auth.verifyIdToken({idToken: token, audience });
if (ticket.getPayload().email !== SA_EMAIL) {
throw new Error('request was signed with different SA');
}
// all good
Read more about Google OpenID Connect Tokens

Deprecation of Google plus

I got a email from Google saying that the use of all Google+ APIs are being shut off. I currently use googleAPI.google.plus to sign people in using Google. Is this plugin going to add a update to support the new way of authorizing users with Google?
Environment details:
OS: Mac OS X
Node.js version: v 10.8.0
npm version: v6.5.0
googleapis version: 33
const googleAPI = require('googleapis');
const plus = googleAPI.google.plus({
version: 'v1',
auth: configs.googleAPIKey // specify your API key here
});
// Check if Google tokens are valid
plus.people.get({
userId: googleUserId,
fields: 'displayName,emails,name,image',
access_token: googleAccessToken
})
.then((user) => {
logger.debug('From google: ' + util.inspect(user.data));
logger.debug('First Name: ' + user.data.name.givenName);
logger.debug('Last Name: ' + user.data.name.familyName);
})
You don't show how you're using that object to do sign-in, so it is a little difficult to answer.
However, the googleapis package already supports sign-ins with an OAuth2 client that you can create with something like
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
You can then get a URL to redirect them to so they can sign-in with something like
const url = oauth2Client.generateAuthUrl({
// If you only need one scope you can pass it as a string
scope: scopes
});
and then redirect them to url. Once they have signed into that URL, they'll be redirected to the URL you have specified as YOUR_REDIRECT_URL which will include a parameter called code. You'll need this code to exchange it for credentials, including the auth token
const {tokens} = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens);
If you just need to use an API Key (which is what your example hints at), then you should just need to include the key the same way you do now for the API calls that you need to make. But that isn't related to authorization.
Since it looks like you want to get profile information, you can use something like userinfo or the People API and choose which fields you want for the user.
Using userinfo might look something like
oauth2client.userinfo.get().then( profile => {
// Handle profile info here
});
The people.get method gives you a little more control, and might look something like
const people = google.people({
version: "v1"
});
const fields = [
"names",
"emailAddresses",
"photos"
];
people.people.get({
resourceName: "people/me",
personFields: fields.join(',')
})
.then( user => {
// Handle the user results here
});

Google Sign-In: backend verification

I have Google Sign-in working on my app: the relevant code is roughly:
var acc = await signInService.signIn();
var auth = await acc.authentication;
var token = auth.idToken;
This gives me a nice long token, which I then pass to my backend with an HTTP POST (this is working fine), and then try to verify. I have the same google-services.json file in my flutter tree and on the backend server (which is nodejs/restify). The backend code is roughly:
let creds = require('./google-services.json');
let auth = require('google-auth-library').OAuth2Client;
let client = new auth(creds.client[0].oauth_client[0].client_id);
. . .
let ticket = await client.verifyIdToken({
idToken: token,
audience: creds.client[0].oauth_client[0].client_id
});
let payload = ticket.getPayload();
This consistently returns my the error "Wrong recipient, payload audience != requiredAudience".
I have also tried registering separately with GCP console and using those keys/client_id instead, but same result. Where can I find the valid client_id that will properly verify this token?
The problem here is the client_id that is being used to create an OAuth2Client and the client_id being used as the audience in the verifyIdToken is the same. The client_id for the audience should be the client_id that was used in your frontend application to get the id_token.
Below is sample code from Google documentation.
const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client(CLIENT_ID);
async function verify() {
const ticket = await client.verifyIdToken({
idToken: token,
audience: CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend
// Or, if multiple clients access the backend:
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
});
const payload = ticket.getPayload();
const userid = payload['sub'];
// If request specified a G Suite domain:
//const domain = payload['hd'];
}
verify().catch(console.error);
And here is the link for the documentation.
Hope this helps.
Another quick solution might be change the name of your param "audience" to "requiredAudience". It works to me. If you copied the code from google, maybe the google documentation is outdated.
client.verifyIdToken({
idToken,
requiredAudience: GOOGLE_CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend
// Or, if multiple clients access the backend:
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
});
It has already been mentioned above that requiredAudience works instead of audience, but I noticed requiredAudience works for both {client_id : <CLIENT_ID>} and <CLIENT_ID>. So maybe you were referencing creds.client[0].oauth_client[0] instead of creds.client[0].oauth_client[0].client_id? I have not been able to find any docs on the difference between requiredAudience and audience, however make sure you are sending just the <CLIENT_ID> instead of {client_id : <CLIENT_ID>}.
Google doc: link
verifyIdToken()'s call signature doesn't require the audience parameter. That's also stated in the changelog. So you can skip it, and it'll work. The documentation is kinda misleading on that.
It's also the reason why using requiredAudience works because it actually isn't being used by the method, so it's the same as not providing it.
I've been faceing this issue with google-auth-library version 8.7.0 and came across a workaround only if you have a single CLIENT_ID to verify.
Once you create your OAuth2Client like this:
const googleClient = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);
You don't need to pass the CLIENT_ID in verifyIdToken function as it uses your googleClient object to create auth url.

Resources