Getting contacts from Google api in node - node.js

I want to get the contacts using the google contacts api in nodejs, but there isn't any quickstart on the developer.google page for nodejs.
I have found this wrapper on github https://github.com/hamdipro/google-contacts-api but I don't understand it and I don't know how to use it.
Can anyone tell me what can I do?

Unfortunately, Google's official API for NodeJS doesn't support Contacts API. They instead use the People API. If you need to access "Other Contacts", you will need Contacts API.
You can still connect with Contacts API using the official googleapis library if you're already using it for other purposes by sending a request to the Contacts API after creating the auth client.
Given that you already have the access token of the user (e.g. if you generated it using Passport, here's the code:
const {google} = require("googleapis");
const authObj = new google.auth.OAuth2({
access_type: 'offline',
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
});
Refresh access token automatically before it expires
authObj.on('tokens', (tokens) => {
const access_token = tokens.access_token
if (tokens.refresh_token){
this.myTokens.refreshToken = tokens.refresh_token
// save refresh token in the database if it exists
}
this.myTokens.accessToken = tokens.access_token
// save new access token (tokens.access_token)
}
authObj.setCredentials({
access_token:this.myTokens.accessToken,
refresh_token:this.myTokens.refreshToken,
});
Make the request to Contacts API:
authObj.request({
headers:{
"GData-Version":3.0
},
params:{
"alt":"json",
//"q":"OPTIONAL SEARCH QUERY",
//"startindex":0
"orderby":"lastmodified",
"sortorder":"descending",
},
url: "https://www.google.com/m8/feeds/contacts/default/full"
}).then( response => {
console.log(response); // extracted contacts
});

First thing instead of going with non-official package mentioned in question you should prefer using official package as they are well maintained, every under the hood changes are handled properly and also issues created are taken into considerations.
Official package for same is here.
Now steps to use above package to get contacts of a user :-
Include googleapis using npm install googleapis --save
Create a service client
var google = require('googleapis');
var contacts = google.people('v1');
Authorise client to make request {Link for authentication docs}
Making authenticated requests
contacts.people.connections.list({
auth: oauth2Client //authetication object generated in step-3
}, function (err, response) {
// handle err and response
});
That should be enough to get user's contact data. Also for authentication if you are using this for domain apart from gmail and have admin access you can get all user's contacts using domain wide delegation otherwise you will have to manually allow access for each user.
Hope it helps. Let me know in comments if have any queries.

Related

Get Google business reviews server side

I'm trying to get a list of reviews of my Google business through the API to display them on my website. But I can't figure out how to authenticate the API server side. The documentation only mentions OAuth2.0 authentication from the client side with redirect URLs, but there won't be a client going to a confirmation page in this case.
I just want to be able to perform this request in Node.js:
GET https://mybusiness.googleapis.com/v4/accounts/{accountId}/locations/{locationId}/reviews
I've already submitted the application and been approved for a Business API and enabled the various APIs in my account. I have created OAuth2.0 credentials. I'm just not sure how to move forward from here.
How can I authenticate Google Business API requests on the server?
I ended up putting together an answer through lots of searching. Google documentation is all over the place.
A basic example of getting reviews is below. But to get it to work there are a few steps first.
You'll need to add a Service Account in your API credentials page
The name, ID, and description aren't particularly important. Just something that makes sense to you
Go to the service account details -> keys -> add key -> create new key -> JSON
This will download a key file to your computer. Keep it private.
Grant domain wide delegation for your service account
To do this, you'll need to be an admin of the account if you're part of an organisation
It will ask for a Client ID, but it is called Unique ID in the service account details. They're the same thing.
Add whatever scopes you need for the services you want to access. For reviews, the scope listed in the example below is enough.
The subject field in google.auth.JWT needs to be an admin of the account. I used my own email.
That should be it! You should now be able to fill out the values in the example below and access the API from a server. Other services may require different scopes.
You can get account and location info from the API docs. The endpoints and data formats are fairly well documented. Just authentication isn't very well explained it seems.
import axios from 'axios';
import {google} from 'googleapis';
import key from './key.json' assert {type: 'json'};
main();
async function main(){
const reviews=await getReviews();
}
async function getReviews(){
const token=await authenticate();
const accountId='YOUR ACCOUNT ID';
const locationId='YOUR LOCATION ID';
const url=`https://mybusiness.googleapis.com/v4/accounts/`+
`${accountId}/locations/${locationId}/reviews`;
const resp=await axios.get(url, {
headers: {
authorization: `Bearer ${token}`
}
});
return resp.data.reviews;
}
async function authenticate(){
const scopes=[
'https://www.googleapis.com/auth/business.manage'
];
const jwt=new google.auth.JWT({
email: key.client_email,
key: key.private_key,
subject: 'ADMIN EMAIL',
scopes
});
const resp=await jwt.authorize();
return resp.access_token.replace(/\.{2,}/g, '');
}

Auth0 & Dialogflow Authentication

I would like to use Auth0 to gain access for Google APIs. Was trying to follow the instructions on this post
Currently to trigger Auth0, I used conv.ask(new SignIn()); and app.intent("actions_intent_SIGN_IN", (conv, params, signin) => { ... })
I get a token from const code = conv.user.access.token; in my actions_intent_SIGN_IN.
However, it seems that this token isn't the token that is used to gain an access_token for Google, aka thru POST /oauth/token. Whatever this token is, it seems like it doesn't work for any of the requests except GET /userinfo. On Google Cloud Functions, I get this on my log:
{ error: 'invalid_grant', error_description: 'Invalid authorization code' }
I played around for a bit with Postman and managed to retrieve the (seemingly?) correct authorization code that can be used for POST /oauth/token thru GET /authorize and building my own url like https://[APP NAME].auth0.com/authorize?response_type=code&client_id=[CLIENT ID]&redirect_uri=[REDIRECT URI]. The authorization code appeared in https://[APP NAME].auth0.com/login/callback?code=[CODE HERE]
The issue is - how do I retrieve the code=[CODE HERE] from dialogflow?
You can authenticate with service accounts that use OAuth2.0 -- you can read more about that in general here and they'll save you a network call. You'll also need to find the appropriate Google API scope(s) here. Dialogflow has samples that show how this is done on Github, for example.
const {google} = require('googleapis');
const serviceAccount = { }; // Enter Service Account private key JSON
const client = new google.auth.JWT({
email: serviceAccount.client_email,
key: serviceAccount.private_key,
scopes: ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
});

CRON Node.js Gmail API script

How do I properly setup Gmail API script that sends emails?
I am about to use this method and I started building my script from this quickstart guide.
Is there alternative way to do this without using OAuth 2 validation? Or a way to validate once for all?
Well, in using Gmail APi with your app, you need to use OAuth 2.0 because all request to the Gmail API must be authorized by an authenticated user. And if you notice the quickstart, there is a step here that you need to create a credentials/Outh client ID to make this API work.
For more information, there is another way to authorize your app with Gmail. You can do it with the help of Google+ Sign-in that provide a "sign-in with Google" authentication method for your app.
While asking for authorization from GMail, OAuth 2.0 gives one access token and one refresh token. To avoid validation every time, store the access token. Use the refresh token to get the new access token after it is expired (access token expires every one hour).
Read about this process here: https://developers.google.com/identity/protocols/OAuth2
I found solution using JWT to authorize OAuth2.
You need to have admin account to create Domain wide delegation service account. Then in Developer console you need to download service key JSON file which you load as credentials.
First fetch all users like this: (here you need to use account with admin directory rights)
const google = require('googleapis');
const gmail = google.gmail('v1');
const directory = google.admin('directory_v1');
const scopes = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/admin.directory.user.readonly'
];
const key = require('./service_key.json');
var authClient = new google.auth.JWT(
key.client_email,
key,
key.private_key,
scopes,
"authorized#mail.com"
);
authClient.authorize(function(err, tokens){
if (err) {
console.log(err);
return;
}
directory.users.list(
{
auth: authClient,
customer: 'my_customer',
maxResults: 250,
orderBy: 'email'
}, (err, resp) => {
if (err) {
console.log(err);
return;
}
console.log(resp);
});
});
Then you need to fetch Thread lists (100 per request (page)). And for each thread object you need to call get method for full thread. When using Gmail API authorize as user you want to fetch emails from. In request as userId use value 'me'.

Oauth2 flow without redirect_uri

I am creating an Android/iOS app which communicates with a Node.js server and would like to identify them securely on my server using Google (and/or Facebook) and OAuth2. I've looked at the following documentation: https://developers.google.com/+/web/signin/server-side-flow
I do not need authorization, I only need authentication (I only want to make sure that the person calling my Node.js service is the person they say they are). To achieve this, if I understand properly, I have to let the user log in using Google on the client side, this will give them an authorization_code which they can then give to my server. My server can then exchange that code for an access_token, and therefore retrieve information about the user. I am then guaranteed that the user is the person they say they are.
The Google documentations (link above) says: "In the Authorized redirect URI field, delete the default value. It is not used for this case.", however, for my server to exchange the authorization_code for an access_token, it needs to provide a redirect_uri, am I missing something?
The redirect_uri is useless for Unity games, for instance (since logging in with Google simply opens a new "window", which is closed when logged in, no redirection involved).
TL;DR
How do you use OAuth2 to authenticate users between my client and my server without redirection?
TL;DR How do you use OAuth2 to authenticate users between my client and my server without redirection?
You can't. OAuth requires that the user is directed to an authorization (and possibly login) screen, and then redirected back to your app.
EDIT 20/12/22. See comment below regarding latest status
Have you looked at this documentation? https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi
Choosing a redirect URI
When you create a client ID in the Google Developers Console, two
redirect_uris are created for you: urn:ietf:wg:oauth:2.0:oob and
http://localhost. The value your application uses determines how the
authorization code is returned to your application.
http://localhost
This value signals to the Google Authorization Server that the
authorization code should be returned as a query string parameter to
the web server on the client. You may specify a port number without
changing the Google Developers Console configuration. To receive the
authorization code using this URL, your application must be listening
on the local web server. This is possible on many, but not all,
platforms. If your platform supports it, this is the recommended
mechanism for obtaining the authorization code.
I had this problem and it took me ages to find the "postmessage" solution that Nepoxx mentions in the comments of the accepted answer here.
For clarification, here's what worked for me.
Follow steps 1-6 here: https://developers.google.com/identity/sign-in/web/server-side-flow
Install googleapis library npm install --save googleapis
For the server-side token exchange do this:
var googleapis = require('googleapis');
var OAuth2 = googleapis.auth.OAuth2;
var oauth2Client = new OAuth2(
GOOGLE_SSO_CLIENT_ID,
GOOGLE_SSO_CLIENT_SECRET,
'postmessage' // this is where you might otherwise specifiy a redirect_uri
);
oauth2Client.getToken(CODE_FROM_STEP_5_OF_INSTRUCTIONS, function(err, tokens) {
// Now tokens contains an access_token and an optional refresh_token. Save them.
});
The redirect_uri can be a URL with a custom URL scheme for which the client registered a handler. This is described here: What's a redirect URI? how does it apply to iOS app for OAuth2.0?. It is not so much about "redirecting" it is about a callback endpoint to your app.
And it become really easy if you use VueJS with https://github.com/guruahn/vue-google-oauth2
Client side
import GAuth from 'vue-google-oauth2'
Vue.use(GAuth, {
clientId: 'xxxxxxx.apps.googleusercontent.com',
scope: 'profile',
})
async signWithGoogle() {
const code = await this.$gAuth.getAuthCode() //
console.log(code ) // { code: 'x/xxxxxxxxxx' }
// send the code to your auth server
// and retrieve a JWT or something to keep in localstorage
// to send on every request and compare with database
}
Server side
import { google } from 'googleapis'
const oauth2Client = new google.auth.OAuth2(GOOGLE_ID, GOOGLE_SECRET, 'postmessage')
google.options({ auth: oauth2Client })
async function getAccount(code) {
// the code you sent with the client
const { tokens } = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens)
const oauth2 = google.oauth2({ version: 'v2' })
const { data: { id } } = await oauth2.userinfo.get()
// there you have the id of the user to store it in the database
// and send it back in a JWT
}

iOS & node.js: how to verify passed access token?

I have an iOS which uses OAuth and OAuth2 providers (Facebook, google, twitter, etc) to validate a user and provide access tokens. Apart from minimal data such as name and email address, the app doesn't uses these services for anything except authentication.
The app then sends the access token to a server to indicate that the user is authenticated.
The server is written in Node.js and before doing anything it needs to validate the supplied access token against the correct OAuth* service.
I've been looking around, but so far all the node.js authentication modules I've found appear to be for logging in and authenticating through web pages supplied by the server.
Does anyone know any node.js modules that can do simple validation of a supplied access token?
To the best of my knowledge (and as far as I can tell from reading the specifications) the OAuth and OAuth 2 specs do not specify a single endpoint for access token validation. That means you will need custom code for each of the providers to validate an access token only.
I looked up what to do for the endpoints you specified:
Facebook
It seems others have used the graph API's 'me' endpoint for Facebook to check if the token is valid. Basically, request:
https://graph.facebook.com/me?access_token={accessToken}
Google
Google have a dedicated debugging endpoint for getting access token information, with nice documentation, too. Basically, request:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={accessToken}
However, they recommend that you don't do this for production:
The tokeninfo endpoint is useful for debugging but for production
purposes, retrieve Google's public keys from the keys endpoint and
perform the validation locally. You should retrieve the keys URI from
the Discovery document using the jwks_uri metadata value. Requests to
the debugging endpoint may be throttled or otherwise subject to
intermittent errors.
Since Google changes its public keys only infrequently, you can cache
them using the cache directives of the HTTP response and, in the vast
majority of cases, perform local validation much more efficiently than
by using the tokeninfo endpoint. This validation requires retrieving
and parsing certificates, and making the appropriate cryptographic
calls to check the signature. Fortunately, there are well-debugged
libraries available in a wide variety of languages to accomplish this
(see jwt.io).
Twitter
Twitter doesn't seem to have a really obvious way to do this. I would suspect that because the account settings data is pretty static, that might be the best way of verifying (fetching tweets would presumably have a higher latency?), so you can request (with the appropriate OAuth signature etc.):
https://api.twitter.com/1.1/account/settings.json
Note that this API is rate-limited to 15 times per window.
All in all this seems trickier than it would first appear. It might be a better idea to implement some kind of session/auth support on the server. Basically, you could verify the external OAuth token you get once, and then assign the user some session token of your own with which you authenticate with the user ID (email, FB id, whatever) on your own server, rather than continuing to make requests to the OAuth providers for every request you get yourself.
For google in production, install google-auth-library (npm install google-auth-library --save) and use the following:
const { OAuth2Client } = require('google-auth-library');
const client = new OAuth2Client(GOOGLE_CLIENT_ID); // Replace by your client ID
async function verifyGoogleToken(token) {
const ticket = await client.verifyIdToken({
idToken: token,
audience: GOOGLE_CLIENT_ID // Replace by your client ID
});
const payload = ticket.getPayload();
return payload;
}
router.post("/auth/google", (req, res, next) => {
verifyGoogleToken(req.body.idToken).then(user => {
console.log(user); // Token is valid, do whatever you want with the user
})
.catch(console.error); // Token invalid
});
More info on Authenticate google token with a backend server, examples for node.js, java, python and php can be found.
For Facebook, do an https request like:
const https = require('https');
router.post("/auth/facebook", (req, res, next) => {
const options = {
hostname: 'graph.facebook.com',
port: 443,
path: '/me?access_token=' + req.body.authToken,
method: 'GET'
}
const request = https.get(options, response => {
response.on('data', function (user) {
user = JSON.parse(user.toString());
console.log(user);
});
})
request.on('error', (message) => {
console.error(message);
});
request.end();
})
In production for google you can use:
https://www.npmjs.com/package/google-auth-library
const ticket = client.verifyIdToken({
idToken: ctx.request.body.idToken,
audience: process.env.GOOGLE_CLIENTID
})
To get info about token from Google use, be careful vith version api
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={accessToken}

Resources