Search code examples
node.jsexpresspassport.jsgoogle-oauthgoogle-fit

How to get Google Fitness API data using OAuth2 with PassportJS


I'm having problems getting the data from the Google Fitness API to use into my application, using Node and Express. Here's a portion of the app.js:

app.get('/auth/google', 
    passport.authenticate('google', 
        { scope: ['profile', 'https://www.googleapis.com/auth/fitness.activity.write'] }
));
app.get('<callback url>', 
    passport.authenticate('google'), (req, res) => {
        res.json(req.user);
});

As you see I'm requesting for 2 distinct scopes. Here's my strategy using passport-google-oauth20 Here's my strategy for this particular datapoints of the passport.js:

passport.use(
    new GoogleStrategy({
        clientID: keys.google.clientID,
        clientSecret: keys.google.clientSecret,
        callbackURL:'<callback url>'
    }, (accessToken, refreshToken, profile, done) => {
            console.log(profile);
        } 
    )
)

The problem however, is that in the console, I only get the first scope "profile" with all its properties but there's no fitness related info. Any idea what's wrong with it? Should I use a different strategy implementation? At the moment, this code hangs to the sign in of google and console logs the profile info which is normal.

Any ideas? Thanks.


Solution

  • I figured it out thanks to @griFlo's comment. Once I obtained the access token from the authentication process, I had to use this and every other that's been generated to call the api I wanted, which I did using a request promise from the request-promise module inside the strategy.

    First install the module using npm i request-promise and require the module to the topside of your app. The code should look like this:

    //other defines
    ...
    const request = require('request-promise');
    
    passport.use(
        new GoogleStrategy({
            // options for google strategy
            clientID: keys.google.clientID,
            clientSecret: keys.google.clientSecret,
            callbackURL:'<callback url>'
        }, (accessToken, refreshToken, profile, done) => {
                User.findOne({googleId: profile.id}).then((currentUser) => {
                    if (currentUser){
                        // check user
                        done(null, currentUser);
                    } else {
                        //call fitness api
                        url = keys.google.fitnessUrl;
                        request.get(url).auth(null, null, true, accessToken)
                          .then(res=> {
                            new User({
                                    googleId: profile.id,
                                    ....
                                    activity: res
                                }
                            ).save().then((newUser) => {
                               done(null, newUser);
                          });  
                        });
                    } 
            });
    }));
    

    The important part is within the mongoose promise part where you check the user before calling the api so you can add the fetched data into the pre-defined schema and save it.