Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sync contacts using Google Contacts API version 3.0 and NodeJS' Passport

I am using passport, and would like to use the Google Contacts API version 3.0 to sync Google contacts with my application (which would suddenly become 10 times more useful).

Has anybody done this? If so, do you have some example code? Is it even possible to use passport authentication to get it all working?

like image 769
Merc Avatar asked Feb 05 '14 00:02

Merc


2 Answers

This comes in two parts, authorization, and then the actual request.

It is basically using OAuth2 protocol, where you redirect the client to google url with scopes(You must at least have https://www.google.com/m8/feeds in your scopes to be able to read and write contacts) and your client id/secret(get them by registering your app. Then google will redirect the user back with the access token on the URL.

You don't need to do this yourself, because there are different modules that already does this:

  • passport-google-oauth

    This makes it easy and assuming you are already using passport, this probably what you want. It is written by the author of passportjs. Just follow the example in it for OAuth 2.0 strategy. Note that you need to you add the right scopes when you are calling passport.authenticate('google', ...). This module when it gets the token, it will get the user profile, so you have to have one of the 3 scopes below:

    passport.authenticate('google', { scope: [ // One of the next three `auth` scopes are needed.
        'https://www.googleapis.com/auth/userinfo.profile',
        'https://www.googleapis.com/auth/userinfo.email',
        'https://www.googleapis.com/auth/plus.login',
        'https://www.google.com/m8/feeds'
    ] }),
    
  • googleapis

    This is module is officially supported by google and created by google employees. You can use it to authenticate, but sadly it doesn't support gData, which contains google contacts. You can check the example to see how you can get the token. You only need the m8/feeds scope with this module, no need for the other ones if you don't want to get the user profile.

  • gdata-js

    This is a non-popular non-maintaining module, but it is more lightweight than the previous two modules. It might need a little polishing out of the box. I suggest also reading the source for understanding the api right.

Once you got the tokens, then you go for the slightly easier part, making the requests and getting the data.

If you read the docs, it's actually very easy. For example to get all contacts(almost all, it's paginated), you need to make a GET request to this url:

https://www.google.com/m8/feeds/contacts/default/full?alt=json&oauth_token=THE_ACCESS_TOKEN

Again there are many modules that can help you in this.

  • google-contacts
  • node-gdata
  • gdata-js Read the source to understand it's api. It's pretty easy actually:

    var client = require('gdata-js')(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET);
    client.setToken({ access_token: accessToken, refresh_token: refreshToken });
    client.getFeed('https://www.google.com/m8/feeds/contacts/default/full', function (err, result) { ... });
    
like image 113
Farid Nouri Neshat Avatar answered Nov 15 '22 12:11

Farid Nouri Neshat


Google's official API for NodeJS doesn't support Contacts API, only the People API.

You can 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 (Google uses Gaxios for making the requests to their APIs although it's not documented officially in googleapis, so just be aware that they might change remove/change the request call in the future without documenting it)

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
});
like image 32
Abdallah Absi Avatar answered Nov 15 '22 11:11

Abdallah Absi